xref: /titanic_50/usr/src/uts/common/fs/namefs/namevfs.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5facf4a8dSllai1  * Common Development and Distribution License (the "License").
6facf4a8dSllai1  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22134a1f4eSCasper H.S. Dik  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
267c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * This file supports the vfs operations for the NAMEFS file system.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/param.h>
357c478bd9Sstevel@tonic-gate #include <sys/systm.h>
367c478bd9Sstevel@tonic-gate #include <sys/debug.h>
377c478bd9Sstevel@tonic-gate #include <sys/errno.h>
387c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
397c478bd9Sstevel@tonic-gate #include <sys/inline.h>
407c478bd9Sstevel@tonic-gate #include <sys/file.h>
417c478bd9Sstevel@tonic-gate #include <sys/proc.h>
427c478bd9Sstevel@tonic-gate #include <sys/stat.h>
437c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
447c478bd9Sstevel@tonic-gate #include <sys/mount.h>
457c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
467c478bd9Sstevel@tonic-gate #include <sys/var.h>
477c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
48aa59c4cbSrsb #include <sys/vfs_opreg.h>
497c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
507c478bd9Sstevel@tonic-gate #include <sys/mode.h>
517c478bd9Sstevel@tonic-gate #include <sys/pcb.h>
527c478bd9Sstevel@tonic-gate #include <sys/signal.h>
537c478bd9Sstevel@tonic-gate #include <sys/user.h>
547c478bd9Sstevel@tonic-gate #include <sys/uio.h>
557c478bd9Sstevel@tonic-gate #include <sys/cred.h>
567c478bd9Sstevel@tonic-gate #include <sys/fs/namenode.h>
577c478bd9Sstevel@tonic-gate #include <sys/stream.h>
587c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
597c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
607c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
617c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h>
627c478bd9Sstevel@tonic-gate #include <sys/policy.h>
637c478bd9Sstevel@tonic-gate #include <sys/vmem.h>
64facf4a8dSllai1 #include <sys/fs/sdev_impl.h>
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #define	NM_INOQUANT		(64 * 1024)
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate /*
697c478bd9Sstevel@tonic-gate  * Define global data structures.
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate dev_t	namedev;
727c478bd9Sstevel@tonic-gate int	namefstype;
737c478bd9Sstevel@tonic-gate struct	namenode *nm_filevp_hash[NM_FILEVP_HASH_SIZE];
747c478bd9Sstevel@tonic-gate struct	vfs namevfs;
757c478bd9Sstevel@tonic-gate kmutex_t ntable_lock;
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate static vmem_t	*nm_inoarena;	/* vmem arena to allocate inode no's from */
787c478bd9Sstevel@tonic-gate static kmutex_t	nm_inolock;
797c478bd9Sstevel@tonic-gate 
808c819381Spf199842 vfsops_t *namefs_vfsops;
817c478bd9Sstevel@tonic-gate /*
827c478bd9Sstevel@tonic-gate  * Functions to allocate node id's starting from 1. Based on vmem routines.
837c478bd9Sstevel@tonic-gate  * The vmem arena is extended in NM_INOQUANT chunks.
847c478bd9Sstevel@tonic-gate  */
857c478bd9Sstevel@tonic-gate uint64_t
namenodeno_alloc(void)867c478bd9Sstevel@tonic-gate namenodeno_alloc(void)
877c478bd9Sstevel@tonic-gate {
887c478bd9Sstevel@tonic-gate 	uint64_t nno;
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	mutex_enter(&nm_inolock);
917c478bd9Sstevel@tonic-gate 	nno = (uint64_t)(uintptr_t)
927c478bd9Sstevel@tonic-gate 	    vmem_alloc(nm_inoarena, 1, VM_NOSLEEP + VM_FIRSTFIT);
937c478bd9Sstevel@tonic-gate 	if (nno == 0) {
947c478bd9Sstevel@tonic-gate 		(void) vmem_add(nm_inoarena, (void *)(vmem_size(nm_inoarena,
957c478bd9Sstevel@tonic-gate 		    VMEM_ALLOC | VMEM_FREE) + 1), NM_INOQUANT, VM_SLEEP);
967c478bd9Sstevel@tonic-gate 		nno = (uint64_t)(uintptr_t)
977c478bd9Sstevel@tonic-gate 		    vmem_alloc(nm_inoarena, 1, VM_SLEEP + VM_FIRSTFIT);
987c478bd9Sstevel@tonic-gate 		ASSERT(nno != 0);
997c478bd9Sstevel@tonic-gate 	}
1007c478bd9Sstevel@tonic-gate 	mutex_exit(&nm_inolock);
1017c478bd9Sstevel@tonic-gate 	ASSERT32(nno <= ULONG_MAX);
1027c478bd9Sstevel@tonic-gate 	return (nno);
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate static void
namenodeno_init(void)1067c478bd9Sstevel@tonic-gate namenodeno_init(void)
1077c478bd9Sstevel@tonic-gate {
1087c478bd9Sstevel@tonic-gate 	nm_inoarena = vmem_create("namefs_inodes", (void *)1, NM_INOQUANT, 1,
1097c478bd9Sstevel@tonic-gate 	    NULL, NULL, NULL, 1, VM_SLEEP);
1107c478bd9Sstevel@tonic-gate 	mutex_init(&nm_inolock, NULL, MUTEX_DEFAULT, NULL);
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate void
namenodeno_free(uint64_t nn)1147c478bd9Sstevel@tonic-gate namenodeno_free(uint64_t nn)
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate 	void *vaddr = (void *)(uintptr_t)nn;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	ASSERT32((uint64_t)(uintptr_t)vaddr == nn);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	mutex_enter(&nm_inolock);
1217c478bd9Sstevel@tonic-gate 	vmem_free(nm_inoarena, vaddr, 1);
1227c478bd9Sstevel@tonic-gate 	mutex_exit(&nm_inolock);
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * Insert a namenode into the nm_filevp_hash table.
1277c478bd9Sstevel@tonic-gate  *
1287c478bd9Sstevel@tonic-gate  * Each link has a unique namenode with a unique nm_mountvp field.
1297c478bd9Sstevel@tonic-gate  * The nm_filevp field of the namenode need not be unique, since a
1307c478bd9Sstevel@tonic-gate  * file descriptor may be mounted to multiple nodes at the same time.
1317c478bd9Sstevel@tonic-gate  * We hash on nm_filevp since that's what discriminates the searches
1327c478bd9Sstevel@tonic-gate  * in namefind() and nm_unmountall().
1337c478bd9Sstevel@tonic-gate  */
1347c478bd9Sstevel@tonic-gate void
nameinsert(struct namenode * nodep)1357c478bd9Sstevel@tonic-gate nameinsert(struct namenode *nodep)
1367c478bd9Sstevel@tonic-gate {
1377c478bd9Sstevel@tonic-gate 	struct namenode **bucket;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ntable_lock));
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	bucket = NM_FILEVP_HASH(nodep->nm_filevp);
1427c478bd9Sstevel@tonic-gate 	nodep->nm_nextp = *bucket;
1437c478bd9Sstevel@tonic-gate 	*bucket = nodep;
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate /*
1477c478bd9Sstevel@tonic-gate  * Remove a namenode from the hash table, if present.
1487c478bd9Sstevel@tonic-gate  */
1497c478bd9Sstevel@tonic-gate void
nameremove(struct namenode * nodep)1507c478bd9Sstevel@tonic-gate nameremove(struct namenode *nodep)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate 	struct namenode *np, **npp;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ntable_lock));
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	for (npp = NM_FILEVP_HASH(nodep->nm_filevp); (np = *npp) != NULL;
1577c478bd9Sstevel@tonic-gate 	    npp = &np->nm_nextp) {
1587c478bd9Sstevel@tonic-gate 		if (np == nodep) {
1597c478bd9Sstevel@tonic-gate 			*npp = np->nm_nextp;
1607c478bd9Sstevel@tonic-gate 			return;
1617c478bd9Sstevel@tonic-gate 		}
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate  * Search for a namenode that has a nm_filevp == vp and nm_mountpt == mnt.
1677c478bd9Sstevel@tonic-gate  * If mnt is NULL, return the first link with nm_filevp of vp.
1687c478bd9Sstevel@tonic-gate  * Returns namenode pointer on success, NULL on failure.
1697c478bd9Sstevel@tonic-gate  */
1707c478bd9Sstevel@tonic-gate struct namenode *
namefind(vnode_t * vp,vnode_t * mnt)1717c478bd9Sstevel@tonic-gate namefind(vnode_t *vp, vnode_t *mnt)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	struct namenode *np;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ntable_lock));
1767c478bd9Sstevel@tonic-gate 	for (np = *NM_FILEVP_HASH(vp); np != NULL; np = np->nm_nextp)
1777c478bd9Sstevel@tonic-gate 		if (np->nm_filevp == vp &&
1787c478bd9Sstevel@tonic-gate 		    (mnt == NULL || np->nm_mountpt == mnt))
1797c478bd9Sstevel@tonic-gate 			break;
1807c478bd9Sstevel@tonic-gate 	return (np);
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate  * Force the unmouting of a file descriptor from ALL of the nodes
1857c478bd9Sstevel@tonic-gate  * that it was mounted to.
1867c478bd9Sstevel@tonic-gate  * At the present time, the only usage for this routine is in the
1877c478bd9Sstevel@tonic-gate  * event one end of a pipe was mounted. At the time the unmounted
1887c478bd9Sstevel@tonic-gate  * end gets closed down, the mounted end is forced to be unmounted.
1897c478bd9Sstevel@tonic-gate  *
1907c478bd9Sstevel@tonic-gate  * This routine searches the namenode hash list for all namenodes
1917c478bd9Sstevel@tonic-gate  * that have a nm_filevp field equal to vp. Each time one is found,
1927c478bd9Sstevel@tonic-gate  * the dounmount() routine is called. This causes the nm_unmount()
1937c478bd9Sstevel@tonic-gate  * routine to be called and thus, the file descriptor is unmounted
1947c478bd9Sstevel@tonic-gate  * from the node.
1957c478bd9Sstevel@tonic-gate  *
1967c478bd9Sstevel@tonic-gate  * At the start of this routine, the reference count for vp is
1977c478bd9Sstevel@tonic-gate  * incremented to protect the vnode from being released in the
1987c478bd9Sstevel@tonic-gate  * event the mount was the only thing keeping the vnode active.
1997c478bd9Sstevel@tonic-gate  * If that is the case, the VOP_CLOSE operation is applied to
2007c478bd9Sstevel@tonic-gate  * the vnode, prior to it being released.
2017c478bd9Sstevel@tonic-gate  */
2027c478bd9Sstevel@tonic-gate static int
nm_umountall(vnode_t * vp,cred_t * crp)2037c478bd9Sstevel@tonic-gate nm_umountall(vnode_t *vp, cred_t *crp)
2047c478bd9Sstevel@tonic-gate {
2057c478bd9Sstevel@tonic-gate 	vfs_t *vfsp;
2067c478bd9Sstevel@tonic-gate 	struct namenode *nodep;
2077c478bd9Sstevel@tonic-gate 	int error = 0;
2087c478bd9Sstevel@tonic-gate 	int realerr = 0;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	/*
2117c478bd9Sstevel@tonic-gate 	 * For each namenode that is associated with the file:
2127c478bd9Sstevel@tonic-gate 	 * If the v_vfsp field is not namevfs, dounmount it.  Otherwise,
2137c478bd9Sstevel@tonic-gate 	 * it was created in nm_open() and will be released in time.
2147c478bd9Sstevel@tonic-gate 	 * The following loop replicates some code from nm_find.  That
2157c478bd9Sstevel@tonic-gate 	 * routine can't be used as is since the list isn't strictly
2167c478bd9Sstevel@tonic-gate 	 * consumed as it is traversed.
2177c478bd9Sstevel@tonic-gate 	 */
2187c478bd9Sstevel@tonic-gate 	mutex_enter(&ntable_lock);
2197c478bd9Sstevel@tonic-gate 	nodep = *NM_FILEVP_HASH(vp);
2207c478bd9Sstevel@tonic-gate 	while (nodep) {
2217c478bd9Sstevel@tonic-gate 		if (nodep->nm_filevp == vp &&
2228c819381Spf199842 		    (vfsp = NMTOV(nodep)->v_vfsp) != NULL &&
2238c819381Spf199842 		    vfsp != &namevfs && (NMTOV(nodep)->v_flag & VROOT)) {
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 			/*
226d5dbd18dSbatschul 			 * If the vn_vfswlock fails, skip the vfs since
2277c478bd9Sstevel@tonic-gate 			 * somebody else may be unmounting it.
2287c478bd9Sstevel@tonic-gate 			 */
229d5dbd18dSbatschul 			if (vn_vfswlock(vfsp->vfs_vnodecovered)) {
2307c478bd9Sstevel@tonic-gate 				realerr = EBUSY;
2317c478bd9Sstevel@tonic-gate 				nodep = nodep->nm_nextp;
2327c478bd9Sstevel@tonic-gate 				continue;
2337c478bd9Sstevel@tonic-gate 			}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 			/*
2367c478bd9Sstevel@tonic-gate 			 * Can't hold ntable_lock across call to do_unmount
2377c478bd9Sstevel@tonic-gate 			 * because nm_unmount tries to acquire it.  This means
2387c478bd9Sstevel@tonic-gate 			 * there is a window where another mount of vp can
2397c478bd9Sstevel@tonic-gate 			 * happen so it is possible that after nm_unmountall
2407c478bd9Sstevel@tonic-gate 			 * there are still some mounts.  This situation existed
2417c478bd9Sstevel@tonic-gate 			 * without MT locking because dounmount can sleep
2427c478bd9Sstevel@tonic-gate 			 * so another mount could happen during that time.
2437c478bd9Sstevel@tonic-gate 			 * This situation is unlikely and doesn't really cause
2447c478bd9Sstevel@tonic-gate 			 * any problems.
2457c478bd9Sstevel@tonic-gate 			 */
2467c478bd9Sstevel@tonic-gate 			mutex_exit(&ntable_lock);
2477c478bd9Sstevel@tonic-gate 			if ((error = dounmount(vfsp, 0, crp)) != 0)
2487c478bd9Sstevel@tonic-gate 				realerr = error;
2497c478bd9Sstevel@tonic-gate 			mutex_enter(&ntable_lock);
2507c478bd9Sstevel@tonic-gate 			/*
2517c478bd9Sstevel@tonic-gate 			 * Since we dropped the ntable_lock, we
2527c478bd9Sstevel@tonic-gate 			 * have to start over from the beginning.
2537c478bd9Sstevel@tonic-gate 			 * If for some reasons dounmount() fails,
2547c478bd9Sstevel@tonic-gate 			 * start from beginning means that we will keep on
2557c478bd9Sstevel@tonic-gate 			 * trying unless another thread unmounts it for us.
2567c478bd9Sstevel@tonic-gate 			 */
2577c478bd9Sstevel@tonic-gate 			nodep = *NM_FILEVP_HASH(vp);
2587c478bd9Sstevel@tonic-gate 		} else
2597c478bd9Sstevel@tonic-gate 			nodep = nodep->nm_nextp;
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 	mutex_exit(&ntable_lock);
2627c478bd9Sstevel@tonic-gate 	return (realerr);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate /*
2667c478bd9Sstevel@tonic-gate  * Force the unmouting of a file descriptor from ALL of the nodes
2677c478bd9Sstevel@tonic-gate  * that it was mounted to.  XXX: fifo_close() calls this routine.
2687c478bd9Sstevel@tonic-gate  *
2697c478bd9Sstevel@tonic-gate  * nm_umountall() may return EBUSY.
2707c478bd9Sstevel@tonic-gate  * nm_unmountall() will keep on trying until it succeeds.
2717c478bd9Sstevel@tonic-gate  */
2727c478bd9Sstevel@tonic-gate int
nm_unmountall(vnode_t * vp,cred_t * crp)2737c478bd9Sstevel@tonic-gate nm_unmountall(vnode_t *vp, cred_t *crp)
2747c478bd9Sstevel@tonic-gate {
2757c478bd9Sstevel@tonic-gate 	int error;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	/*
2787c478bd9Sstevel@tonic-gate 	 * Nm_umuontall() returns only if it succeeds or
2797c478bd9Sstevel@tonic-gate 	 * return with error EBUSY.  If EBUSY, that means
2807c478bd9Sstevel@tonic-gate 	 * it cannot acquire the lock on the covered vnode,
2817c478bd9Sstevel@tonic-gate 	 * and we will keep on trying.
2827c478bd9Sstevel@tonic-gate 	 */
2837c478bd9Sstevel@tonic-gate 	for (;;) {
2847c478bd9Sstevel@tonic-gate 		error = nm_umountall(vp, crp);
2857c478bd9Sstevel@tonic-gate 		if (error != EBUSY)
2867c478bd9Sstevel@tonic-gate 			break;
2877c478bd9Sstevel@tonic-gate 		delay(1);	/* yield cpu briefly, then try again */
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 	return (error);
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate /*
2937c478bd9Sstevel@tonic-gate  * Mount a file descriptor onto the node in the file system.
2947c478bd9Sstevel@tonic-gate  * Create a new vnode, update the attributes with info from the
2957c478bd9Sstevel@tonic-gate  * file descriptor and the mount point.  The mask, mode, uid, gid,
2967c478bd9Sstevel@tonic-gate  * atime, mtime and ctime are taken from the mountpt.  Link count is
2977c478bd9Sstevel@tonic-gate  * set to one, the file system id is namedev and nodeid is unique
2987c478bd9Sstevel@tonic-gate  * for each mounted object.  Other attributes are taken from mount point.
2997c478bd9Sstevel@tonic-gate  * Make sure user is owner (or root) with write permissions on mount point.
3007c478bd9Sstevel@tonic-gate  * Hash the new vnode and return 0.
3017c478bd9Sstevel@tonic-gate  * Upon entry to this routine, the file descriptor is in the
3027c478bd9Sstevel@tonic-gate  * fd field of a struct namefd.  Copy that structure from user
3037c478bd9Sstevel@tonic-gate  * space and retrieve the file descriptor.
3047c478bd9Sstevel@tonic-gate  */
3057c478bd9Sstevel@tonic-gate static int
nm_mount(vfs_t * vfsp,vnode_t * mvp,struct mounta * uap,cred_t * crp)3067c478bd9Sstevel@tonic-gate nm_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *crp)
3077c478bd9Sstevel@tonic-gate {
3087c478bd9Sstevel@tonic-gate 	struct namefd namefdp;
3097c478bd9Sstevel@tonic-gate 	struct vnode *filevp;		/* file descriptor vnode */
3107c478bd9Sstevel@tonic-gate 	struct file *fp;
3117c478bd9Sstevel@tonic-gate 	struct vnode *newvp;		/* vnode representing this mount */
3127469ad70Svikram 	struct vnode *rvp;		/* realvp (if any) for the mountpt */
3137c478bd9Sstevel@tonic-gate 	struct namenode *nodep;		/* namenode for this mount */
3147c478bd9Sstevel@tonic-gate 	struct vattr filevattr;		/* attributes of file dec.  */
3157c478bd9Sstevel@tonic-gate 	struct vattr *vattrp;		/* attributes of this mount */
3167c478bd9Sstevel@tonic-gate 	char *resource_name;
3177c478bd9Sstevel@tonic-gate 	char *resource_nodetype;
3187c478bd9Sstevel@tonic-gate 	statvfs64_t *svfsp;
3197c478bd9Sstevel@tonic-gate 	int error = 0;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/*
3227c478bd9Sstevel@tonic-gate 	 * Get the file descriptor from user space.
3237c478bd9Sstevel@tonic-gate 	 * Make sure the file descriptor is valid and has an
3247c478bd9Sstevel@tonic-gate 	 * associated file pointer.
3257c478bd9Sstevel@tonic-gate 	 * If so, extract the vnode from the file pointer.
3267c478bd9Sstevel@tonic-gate 	 */
3277c478bd9Sstevel@tonic-gate 	if (uap->datalen != sizeof (struct namefd))
3287c478bd9Sstevel@tonic-gate 		return (EINVAL);
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	if (copyin(uap->dataptr, &namefdp, uap->datalen))
3317c478bd9Sstevel@tonic-gate 		return (EFAULT);
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	if ((fp = getf(namefdp.fd)) == NULL)
3347c478bd9Sstevel@tonic-gate 		return (EBADF);
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	/*
3377c478bd9Sstevel@tonic-gate 	 * If the mount point already has something mounted
3387c478bd9Sstevel@tonic-gate 	 * on it, disallow this mount.  (This restriction may
3397c478bd9Sstevel@tonic-gate 	 * be removed in a later release).
3407c478bd9Sstevel@tonic-gate 	 * Or unmount has completed but the namefs ROOT vnode
3417c478bd9Sstevel@tonic-gate 	 * count has not decremented to zero, disallow this mount.
3427c478bd9Sstevel@tonic-gate 	 */
3438c819381Spf199842 
3447c478bd9Sstevel@tonic-gate 	mutex_enter(&mvp->v_lock);
3458c819381Spf199842 	if ((mvp->v_flag & VROOT) ||
3468c819381Spf199842 	    vfs_matchops(mvp->v_vfsp, namefs_vfsops)) {
3477c478bd9Sstevel@tonic-gate 		mutex_exit(&mvp->v_lock);
3487c478bd9Sstevel@tonic-gate 		releasef(namefdp.fd);
3497c478bd9Sstevel@tonic-gate 		return (EBUSY);
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 	mutex_exit(&mvp->v_lock);
3527c478bd9Sstevel@tonic-gate 
353facf4a8dSllai1 	/*
354facf4a8dSllai1 	 * Cannot allow users to fattach() in /dev/pts.
355facf4a8dSllai1 	 * First, there is no need for doing so and secondly
356aecfc01dSrui zang - Sun Microsystems - Beijing China 	 * we cannot allow arbitrary users to park on a node in
357aecfc01dSrui zang - Sun Microsystems - Beijing China 	 * /dev/pts or /dev/vt.
358facf4a8dSllai1 	 */
3597469ad70Svikram 	rvp = NULLVP;
3607469ad70Svikram 	if (vn_matchops(mvp, spec_getvnodeops()) &&
361da6c28aaSamw 	    VOP_REALVP(mvp, &rvp, NULL) == 0 && rvp &&
362aecfc01dSrui zang - Sun Microsystems - Beijing China 	    (vn_matchops(rvp, devpts_getvnodeops()) ||
363aecfc01dSrui zang - Sun Microsystems - Beijing China 	    vn_matchops(rvp, devvt_getvnodeops()))) {
364facf4a8dSllai1 		releasef(namefdp.fd);
365facf4a8dSllai1 		return (ENOTSUP);
366facf4a8dSllai1 	}
367facf4a8dSllai1 
3687c478bd9Sstevel@tonic-gate 	filevp = fp->f_vnode;
3697c478bd9Sstevel@tonic-gate 	if (filevp->v_type == VDIR || filevp->v_type == VPORT) {
3707c478bd9Sstevel@tonic-gate 		releasef(namefdp.fd);
3717c478bd9Sstevel@tonic-gate 		return (EINVAL);
3727c478bd9Sstevel@tonic-gate 	}
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	/*
3757c478bd9Sstevel@tonic-gate 	 * If the fd being mounted refers to neither a door nor a stream,
3767c478bd9Sstevel@tonic-gate 	 * make sure the caller is privileged.
3777c478bd9Sstevel@tonic-gate 	 */
3787c478bd9Sstevel@tonic-gate 	if (filevp->v_type != VDOOR && filevp->v_stream == NULL) {
3797c478bd9Sstevel@tonic-gate 		if (secpolicy_fs_mount(crp, filevp, vfsp) != 0) {
3807c478bd9Sstevel@tonic-gate 			/* fd is neither a stream nor a door */
3817c478bd9Sstevel@tonic-gate 			releasef(namefdp.fd);
3827c478bd9Sstevel@tonic-gate 			return (EINVAL);
3837c478bd9Sstevel@tonic-gate 		}
3847c478bd9Sstevel@tonic-gate 	}
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	/*
3877c478bd9Sstevel@tonic-gate 	 * Make sure the file descriptor is not the root of some
3887c478bd9Sstevel@tonic-gate 	 * file system.
3897c478bd9Sstevel@tonic-gate 	 * If it's not, create a reference and allocate a namenode
3907c478bd9Sstevel@tonic-gate 	 * to represent this mount request.
3917c478bd9Sstevel@tonic-gate 	 */
3927c478bd9Sstevel@tonic-gate 	if (filevp->v_flag & VROOT) {
3937c478bd9Sstevel@tonic-gate 		releasef(namefdp.fd);
3947c478bd9Sstevel@tonic-gate 		return (EBUSY);
3957c478bd9Sstevel@tonic-gate 	}
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	nodep = kmem_zalloc(sizeof (struct namenode), KM_SLEEP);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	mutex_init(&nodep->nm_lock, NULL, MUTEX_DEFAULT, NULL);
4007c478bd9Sstevel@tonic-gate 	vattrp = &nodep->nm_vattr;
4017c478bd9Sstevel@tonic-gate 	vattrp->va_mask = AT_ALL;
402da6c28aaSamw 	if (error = VOP_GETATTR(mvp, vattrp, 0, crp, NULL))
4037c478bd9Sstevel@tonic-gate 		goto out;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	filevattr.va_mask = AT_ALL;
406da6c28aaSamw 	if (error = VOP_GETATTR(filevp, &filevattr, 0, crp, NULL))
4077c478bd9Sstevel@tonic-gate 		goto out;
4087c478bd9Sstevel@tonic-gate 	/*
4097c478bd9Sstevel@tonic-gate 	 * Make sure the user is the owner of the mount point
4107c478bd9Sstevel@tonic-gate 	 * or has sufficient privileges.
4117c478bd9Sstevel@tonic-gate 	 */
4127c478bd9Sstevel@tonic-gate 	if (error = secpolicy_vnode_owner(crp, vattrp->va_uid))
4137c478bd9Sstevel@tonic-gate 		goto out;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	/*
4167c478bd9Sstevel@tonic-gate 	 * Make sure the user has write permissions on the
4177c478bd9Sstevel@tonic-gate 	 * mount point (or has sufficient privileges).
4187c478bd9Sstevel@tonic-gate 	 */
419134a1f4eSCasper H.S. Dik 	if (secpolicy_vnode_access2(crp, mvp, vattrp->va_uid, vattrp->va_mode,
420134a1f4eSCasper H.S. Dik 	    VWRITE) != 0) {
4217c478bd9Sstevel@tonic-gate 		error = EACCES;
4227c478bd9Sstevel@tonic-gate 		goto out;
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	/*
4267c478bd9Sstevel@tonic-gate 	 * If the file descriptor has file/record locking, don't
4277c478bd9Sstevel@tonic-gate 	 * allow the mount to succeed.
4287c478bd9Sstevel@tonic-gate 	 */
4297c478bd9Sstevel@tonic-gate 	if (vn_has_flocks(filevp)) {
4307c478bd9Sstevel@tonic-gate 		error = EACCES;
4317c478bd9Sstevel@tonic-gate 		goto out;
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	/*
4357c478bd9Sstevel@tonic-gate 	 * Initialize the namenode.
4367c478bd9Sstevel@tonic-gate 	 */
4377c478bd9Sstevel@tonic-gate 	if (filevp->v_stream) {
4387c478bd9Sstevel@tonic-gate 		struct stdata *stp = filevp->v_stream;
4397c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
4407c478bd9Sstevel@tonic-gate 		stp->sd_flag |= STRMOUNT;
4417c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 	nodep->nm_filevp = filevp;
4447c478bd9Sstevel@tonic-gate 	mutex_enter(&fp->f_tlock);
4457c478bd9Sstevel@tonic-gate 	fp->f_count++;
4467c478bd9Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	releasef(namefdp.fd);
4497c478bd9Sstevel@tonic-gate 	nodep->nm_filep = fp;
4507c478bd9Sstevel@tonic-gate 	nodep->nm_mountpt = mvp;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	/*
4537c478bd9Sstevel@tonic-gate 	 * The attributes for the mounted file descriptor were initialized
4547c478bd9Sstevel@tonic-gate 	 * above by applying VOP_GETATTR to the mount point.  Some of
4557c478bd9Sstevel@tonic-gate 	 * the fields of the attributes structure will be overwritten
4567c478bd9Sstevel@tonic-gate 	 * by the attributes from the file descriptor.
4577c478bd9Sstevel@tonic-gate 	 */
4587c478bd9Sstevel@tonic-gate 	vattrp->va_type    = filevattr.va_type;
4597c478bd9Sstevel@tonic-gate 	vattrp->va_fsid    = namedev;
4607c478bd9Sstevel@tonic-gate 	vattrp->va_nodeid  = namenodeno_alloc();
4617c478bd9Sstevel@tonic-gate 	vattrp->va_nlink   = 1;
4627c478bd9Sstevel@tonic-gate 	vattrp->va_size    = filevattr.va_size;
4637c478bd9Sstevel@tonic-gate 	vattrp->va_rdev    = filevattr.va_rdev;
4647c478bd9Sstevel@tonic-gate 	vattrp->va_blksize = filevattr.va_blksize;
4657c478bd9Sstevel@tonic-gate 	vattrp->va_nblocks = filevattr.va_nblocks;
4667c478bd9Sstevel@tonic-gate 	vattrp->va_seq	   = 0;
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	/*
4697c478bd9Sstevel@tonic-gate 	 * Initialize new vnode structure for the mounted file descriptor.
4707c478bd9Sstevel@tonic-gate 	 */
4717c478bd9Sstevel@tonic-gate 	nodep->nm_vnode = vn_alloc(KM_SLEEP);
4727c478bd9Sstevel@tonic-gate 	newvp = NMTOV(nodep);
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	newvp->v_flag = filevp->v_flag | VROOT | VNOMAP | VNOSWAP;
4757c478bd9Sstevel@tonic-gate 	vn_setops(newvp, nm_vnodeops);
4767c478bd9Sstevel@tonic-gate 	newvp->v_vfsp = vfsp;
4777c478bd9Sstevel@tonic-gate 	newvp->v_stream = filevp->v_stream;
4787c478bd9Sstevel@tonic-gate 	newvp->v_type = filevp->v_type;
4797c478bd9Sstevel@tonic-gate 	newvp->v_rdev = filevp->v_rdev;
4807c478bd9Sstevel@tonic-gate 	newvp->v_data = (caddr_t)nodep;
4818c819381Spf199842 	VFS_HOLD(vfsp);
4827c478bd9Sstevel@tonic-gate 	vn_exists(newvp);
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	/*
4857c478bd9Sstevel@tonic-gate 	 * Initialize the vfs structure.
4867c478bd9Sstevel@tonic-gate 	 */
4877c478bd9Sstevel@tonic-gate 	vfsp->vfs_vnodecovered = NULL;
4887c478bd9Sstevel@tonic-gate 	vfsp->vfs_flag |= VFS_UNLINKABLE;
4897c478bd9Sstevel@tonic-gate 	vfsp->vfs_bsize = 1024;
4907c478bd9Sstevel@tonic-gate 	vfsp->vfs_fstype = namefstype;
4917c478bd9Sstevel@tonic-gate 	vfs_make_fsid(&vfsp->vfs_fsid, namedev, namefstype);
4927c478bd9Sstevel@tonic-gate 	vfsp->vfs_data = (caddr_t)nodep;
4937c478bd9Sstevel@tonic-gate 	vfsp->vfs_dev = namedev;
4947c478bd9Sstevel@tonic-gate 	vfsp->vfs_bcount = 0;
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	/*
4977c478bd9Sstevel@tonic-gate 	 * Set the name we mounted from.
4987c478bd9Sstevel@tonic-gate 	 */
4997c478bd9Sstevel@tonic-gate 	switch (filevp->v_type) {
5007c478bd9Sstevel@tonic-gate 	case VPROC:	/* VOP_GETATTR() translates this to VREG */
5017c478bd9Sstevel@tonic-gate 	case VREG:	resource_nodetype = "file"; break;
5027c478bd9Sstevel@tonic-gate 	case VDIR:	resource_nodetype = "directory"; break;
5037c478bd9Sstevel@tonic-gate 	case VBLK:	resource_nodetype = "device"; break;
5047c478bd9Sstevel@tonic-gate 	case VCHR:	resource_nodetype = "device"; break;
5057c478bd9Sstevel@tonic-gate 	case VLNK:	resource_nodetype = "link"; break;
5067c478bd9Sstevel@tonic-gate 	case VFIFO:	resource_nodetype = "fifo"; break;
5077c478bd9Sstevel@tonic-gate 	case VDOOR:	resource_nodetype = "door"; break;
5087c478bd9Sstevel@tonic-gate 	case VSOCK:	resource_nodetype = "socket"; break;
5097c478bd9Sstevel@tonic-gate 	default:	resource_nodetype = "resource"; break;
5107c478bd9Sstevel@tonic-gate 	}
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate #define	RESOURCE_NAME_SZ 128 /* Maximum length of the resource name */
5137c478bd9Sstevel@tonic-gate 	resource_name = kmem_alloc(RESOURCE_NAME_SZ, KM_SLEEP);
5147c478bd9Sstevel@tonic-gate 	svfsp = kmem_alloc(sizeof (statvfs64_t), KM_SLEEP);
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	error = VFS_STATVFS(filevp->v_vfsp, svfsp);
5177c478bd9Sstevel@tonic-gate 	if (error == 0) {
5187c478bd9Sstevel@tonic-gate 		(void) snprintf(resource_name, RESOURCE_NAME_SZ,
5197c478bd9Sstevel@tonic-gate 		    "unspecified_%s_%s", svfsp->f_basetype, resource_nodetype);
5207c478bd9Sstevel@tonic-gate 	} else {
5217c478bd9Sstevel@tonic-gate 		(void) snprintf(resource_name, RESOURCE_NAME_SZ,
5227c478bd9Sstevel@tonic-gate 		    "unspecified_%s", resource_nodetype);
5237c478bd9Sstevel@tonic-gate 	}
5247c478bd9Sstevel@tonic-gate 
525*d7de0ceaSRobert Harris 	vfs_setresource(vfsp, resource_name, 0);
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	kmem_free(svfsp, sizeof (statvfs64_t));
5287c478bd9Sstevel@tonic-gate 	kmem_free(resource_name, RESOURCE_NAME_SZ);
5297c478bd9Sstevel@tonic-gate #undef RESOURCE_NAME_SZ
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	/*
5327c478bd9Sstevel@tonic-gate 	 * Insert the namenode.
5337c478bd9Sstevel@tonic-gate 	 */
5347c478bd9Sstevel@tonic-gate 	mutex_enter(&ntable_lock);
5357c478bd9Sstevel@tonic-gate 	nameinsert(nodep);
5367c478bd9Sstevel@tonic-gate 	mutex_exit(&ntable_lock);
5377c478bd9Sstevel@tonic-gate 	return (0);
5387c478bd9Sstevel@tonic-gate out:
5397c478bd9Sstevel@tonic-gate 	releasef(namefdp.fd);
5407c478bd9Sstevel@tonic-gate 	kmem_free(nodep, sizeof (struct namenode));
5417c478bd9Sstevel@tonic-gate 	return (error);
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate /*
5457c478bd9Sstevel@tonic-gate  * Unmount a file descriptor from a node in the file system.
5467c478bd9Sstevel@tonic-gate  * If the user is not the owner of the file and is not privileged,
5477c478bd9Sstevel@tonic-gate  * the request is denied.
5487c478bd9Sstevel@tonic-gate  * Otherwise, remove the namenode from the hash list.
5497c478bd9Sstevel@tonic-gate  * If the mounted file descriptor was that of a stream and this
5507c478bd9Sstevel@tonic-gate  * was the last mount of the stream, turn off the STRMOUNT flag.
5517c478bd9Sstevel@tonic-gate  * If the rootvp is referenced other than through the mount,
5527c478bd9Sstevel@tonic-gate  * nm_inactive will clean up.
5537c478bd9Sstevel@tonic-gate  */
5547c478bd9Sstevel@tonic-gate static int
nm_unmount(vfs_t * vfsp,int flag,cred_t * crp)5557c478bd9Sstevel@tonic-gate nm_unmount(vfs_t *vfsp, int flag, cred_t *crp)
5567c478bd9Sstevel@tonic-gate {
5577c478bd9Sstevel@tonic-gate 	struct namenode *nodep = (struct namenode *)vfsp->vfs_data;
5587c478bd9Sstevel@tonic-gate 	vnode_t *vp, *thisvp;
5597c478bd9Sstevel@tonic-gate 	struct file *fp = NULL;
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	ASSERT((nodep->nm_flag & NMNMNT) == 0);
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	/*
5647c478bd9Sstevel@tonic-gate 	 * forced unmount is not supported by this file system
5657c478bd9Sstevel@tonic-gate 	 * and thus, ENOTSUP, is being returned.
5667c478bd9Sstevel@tonic-gate 	 */
5677c478bd9Sstevel@tonic-gate 	if (flag & MS_FORCE) {
5687c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
5697c478bd9Sstevel@tonic-gate 	}
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	vp = nodep->nm_filevp;
5727c478bd9Sstevel@tonic-gate 	mutex_enter(&nodep->nm_lock);
5737c478bd9Sstevel@tonic-gate 	if (secpolicy_vnode_owner(crp, nodep->nm_vattr.va_uid) != 0) {
5747c478bd9Sstevel@tonic-gate 		mutex_exit(&nodep->nm_lock);
5757c478bd9Sstevel@tonic-gate 		return (EPERM);
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	mutex_exit(&nodep->nm_lock);
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	mutex_enter(&ntable_lock);
5817c478bd9Sstevel@tonic-gate 	nameremove(nodep);
5827c478bd9Sstevel@tonic-gate 	thisvp = NMTOV(nodep);
5837c478bd9Sstevel@tonic-gate 	mutex_enter(&thisvp->v_lock);
5847c478bd9Sstevel@tonic-gate 	if (thisvp->v_count-- == 1) {
5857c478bd9Sstevel@tonic-gate 		fp = nodep->nm_filep;
5867c478bd9Sstevel@tonic-gate 		mutex_exit(&thisvp->v_lock);
5877c478bd9Sstevel@tonic-gate 		vn_invalid(thisvp);
5887c478bd9Sstevel@tonic-gate 		vn_free(thisvp);
5898c819381Spf199842 		VFS_RELE(vfsp);
5907c478bd9Sstevel@tonic-gate 		namenodeno_free(nodep->nm_vattr.va_nodeid);
5917c478bd9Sstevel@tonic-gate 		kmem_free(nodep, sizeof (struct namenode));
5927c478bd9Sstevel@tonic-gate 	} else {
5937c478bd9Sstevel@tonic-gate 		thisvp->v_flag &= ~VROOT;
5947c478bd9Sstevel@tonic-gate 		mutex_exit(&thisvp->v_lock);
5957c478bd9Sstevel@tonic-gate 	}
5967c478bd9Sstevel@tonic-gate 	if (namefind(vp, NULLVP) == NULL && vp->v_stream) {
5977c478bd9Sstevel@tonic-gate 		struct stdata *stp = vp->v_stream;
5987c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
5997c478bd9Sstevel@tonic-gate 		stp->sd_flag &= ~STRMOUNT;
6007c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 	mutex_exit(&ntable_lock);
6037c478bd9Sstevel@tonic-gate 	if (fp != NULL)
6047c478bd9Sstevel@tonic-gate 		(void) closef(fp);
6057c478bd9Sstevel@tonic-gate 	return (0);
6067c478bd9Sstevel@tonic-gate }
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate /*
6097c478bd9Sstevel@tonic-gate  * Create a reference to the root of a mounted file descriptor.
6107c478bd9Sstevel@tonic-gate  * This routine is called from lookupname() in the event a path
6117c478bd9Sstevel@tonic-gate  * is being searched that has a mounted file descriptor in it.
6127c478bd9Sstevel@tonic-gate  */
6137c478bd9Sstevel@tonic-gate static int
nm_root(vfs_t * vfsp,vnode_t ** vpp)6147c478bd9Sstevel@tonic-gate nm_root(vfs_t *vfsp, vnode_t **vpp)
6157c478bd9Sstevel@tonic-gate {
6167c478bd9Sstevel@tonic-gate 	struct namenode *nodep = (struct namenode *)vfsp->vfs_data;
6177c478bd9Sstevel@tonic-gate 	struct vnode *vp = NMTOV(nodep);
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	VN_HOLD(vp);
6207c478bd9Sstevel@tonic-gate 	*vpp = vp;
6217c478bd9Sstevel@tonic-gate 	return (0);
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate /*
6257c478bd9Sstevel@tonic-gate  * Return in sp the status of this file system.
6267c478bd9Sstevel@tonic-gate  */
6277c478bd9Sstevel@tonic-gate static int
nm_statvfs(vfs_t * vfsp,struct statvfs64 * sp)6287c478bd9Sstevel@tonic-gate nm_statvfs(vfs_t *vfsp, struct statvfs64 *sp)
6297c478bd9Sstevel@tonic-gate {
6307c478bd9Sstevel@tonic-gate 	dev32_t d32;
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
6337c478bd9Sstevel@tonic-gate 	sp->f_bsize	= 1024;
6347c478bd9Sstevel@tonic-gate 	sp->f_frsize	= 1024;
6357c478bd9Sstevel@tonic-gate 	(void) cmpldev(&d32, vfsp->vfs_dev);
6367c478bd9Sstevel@tonic-gate 	sp->f_fsid = d32;
6377c478bd9Sstevel@tonic-gate 	(void) strcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name);
6387c478bd9Sstevel@tonic-gate 	sp->f_flag	= vf_to_stf(vfsp->vfs_flag);
6397c478bd9Sstevel@tonic-gate 	return (0);
6407c478bd9Sstevel@tonic-gate }
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate /*
6437c478bd9Sstevel@tonic-gate  * Since this file system has no disk blocks of its own, apply
6447c478bd9Sstevel@tonic-gate  * the VOP_FSYNC operation on the mounted file descriptor.
6457c478bd9Sstevel@tonic-gate  */
6467c478bd9Sstevel@tonic-gate static int
nm_sync(vfs_t * vfsp,short flag,cred_t * crp)6477c478bd9Sstevel@tonic-gate nm_sync(vfs_t *vfsp, short flag, cred_t *crp)
6487c478bd9Sstevel@tonic-gate {
6497c478bd9Sstevel@tonic-gate 	struct namenode *nodep;
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	if (vfsp == NULL)
6527c478bd9Sstevel@tonic-gate 		return (0);
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	nodep = (struct namenode *)vfsp->vfs_data;
6557c478bd9Sstevel@tonic-gate 	if (flag & SYNC_CLOSE)
6567c478bd9Sstevel@tonic-gate 		return (nm_umountall(nodep->nm_filevp, crp));
6577c478bd9Sstevel@tonic-gate 
658da6c28aaSamw 	return (VOP_FSYNC(nodep->nm_filevp, FSYNC, crp, NULL));
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate /*
6627c478bd9Sstevel@tonic-gate  * File system initialization routine. Save the file system type,
6637c478bd9Sstevel@tonic-gate  * establish a file system device number and initialize nm_filevp_hash[].
6647c478bd9Sstevel@tonic-gate  */
6657c478bd9Sstevel@tonic-gate int
nameinit(int fstype,char * name)6667c478bd9Sstevel@tonic-gate nameinit(int fstype, char *name)
6677c478bd9Sstevel@tonic-gate {
6687c478bd9Sstevel@tonic-gate 	static const fs_operation_def_t nm_vfsops_template[] = {
669aa59c4cbSrsb 		VFSNAME_MOUNT,		{ .vfs_mount = nm_mount },
670aa59c4cbSrsb 		VFSNAME_UNMOUNT,	{ .vfs_unmount = nm_unmount },
671aa59c4cbSrsb 		VFSNAME_ROOT,		{ .vfs_root = nm_root },
672aa59c4cbSrsb 		VFSNAME_STATVFS,	{ .vfs_statvfs = nm_statvfs },
673aa59c4cbSrsb 		VFSNAME_SYNC,		{ .vfs_sync = nm_sync },
6747c478bd9Sstevel@tonic-gate 		NULL,			NULL
6757c478bd9Sstevel@tonic-gate 	};
6767c478bd9Sstevel@tonic-gate 	static const fs_operation_def_t nm_dummy_vfsops_template[] = {
677aa59c4cbSrsb 		VFSNAME_STATVFS,	{ .vfs_statvfs = nm_statvfs },
678aa59c4cbSrsb 		VFSNAME_SYNC,		{ .vfs_sync = nm_sync },
6797c478bd9Sstevel@tonic-gate 		NULL,			NULL
6807c478bd9Sstevel@tonic-gate 	};
6817c478bd9Sstevel@tonic-gate 	int error;
6827c478bd9Sstevel@tonic-gate 	int dev;
6837c478bd9Sstevel@tonic-gate 	vfsops_t *dummy_vfsops;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	error = vfs_setfsops(fstype, nm_vfsops_template, &namefs_vfsops);
6867c478bd9Sstevel@tonic-gate 	if (error != 0) {
6877c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "nameinit: bad vfs ops template");
6887c478bd9Sstevel@tonic-gate 		return (error);
6897c478bd9Sstevel@tonic-gate 	}
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	error = vfs_makefsops(nm_dummy_vfsops_template, &dummy_vfsops);
6927c478bd9Sstevel@tonic-gate 	if (error != 0) {
6937c478bd9Sstevel@tonic-gate 		(void) vfs_freevfsops_by_type(fstype);
6947c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "nameinit: bad dummy vfs ops template");
6957c478bd9Sstevel@tonic-gate 		return (error);
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	error = vn_make_ops(name, nm_vnodeops_template, &nm_vnodeops);
6997c478bd9Sstevel@tonic-gate 	if (error != 0) {
7007c478bd9Sstevel@tonic-gate 		(void) vfs_freevfsops_by_type(fstype);
7017c478bd9Sstevel@tonic-gate 		vfs_freevfsops(dummy_vfsops);
7027c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "nameinit: bad vnode ops template");
7037c478bd9Sstevel@tonic-gate 		return (error);
7047c478bd9Sstevel@tonic-gate 	}
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	namefstype = fstype;
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	if ((dev = getudev()) == (major_t)-1) {
7097c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "nameinit: can't get unique device");
7107c478bd9Sstevel@tonic-gate 		dev = 0;
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate 	mutex_init(&ntable_lock, NULL, MUTEX_DEFAULT, NULL);
7137c478bd9Sstevel@tonic-gate 	namedev = makedevice(dev, 0);
7147c478bd9Sstevel@tonic-gate 	bzero(nm_filevp_hash, sizeof (nm_filevp_hash));
7157c478bd9Sstevel@tonic-gate 	vfs_setops(&namevfs, dummy_vfsops);
7167c478bd9Sstevel@tonic-gate 	namevfs.vfs_vnodecovered = NULL;
7177c478bd9Sstevel@tonic-gate 	namevfs.vfs_bsize = 1024;
7187c478bd9Sstevel@tonic-gate 	namevfs.vfs_fstype = namefstype;
7197c478bd9Sstevel@tonic-gate 	vfs_make_fsid(&namevfs.vfs_fsid, namedev, namefstype);
7207c478bd9Sstevel@tonic-gate 	namevfs.vfs_dev = namedev;
7217c478bd9Sstevel@tonic-gate 	return (0);
7227c478bd9Sstevel@tonic-gate }
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate static mntopts_t nm_mntopts = {
7257c478bd9Sstevel@tonic-gate 	NULL,
7267c478bd9Sstevel@tonic-gate 	0
7277c478bd9Sstevel@tonic-gate };
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate static vfsdef_t vfw = {
7307c478bd9Sstevel@tonic-gate 	VFSDEF_VERSION,
7317c478bd9Sstevel@tonic-gate 	"namefs",
7327c478bd9Sstevel@tonic-gate 	nameinit,
7330fbb751dSJohn Levon 	VSW_HASPROTO | VSW_ZMOUNT,
7347c478bd9Sstevel@tonic-gate 	&nm_mntopts
7357c478bd9Sstevel@tonic-gate };
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate /*
7387c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
7397c478bd9Sstevel@tonic-gate  */
7407c478bd9Sstevel@tonic-gate static struct modlfs modlfs = {
7417c478bd9Sstevel@tonic-gate 	&mod_fsops, "filesystem for namefs", &vfw
7427c478bd9Sstevel@tonic-gate };
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
7457c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modlfs, NULL
7467c478bd9Sstevel@tonic-gate };
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate int
_init(void)7497c478bd9Sstevel@tonic-gate _init(void)
7507c478bd9Sstevel@tonic-gate {
7517c478bd9Sstevel@tonic-gate 	namenodeno_init();
7527c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate int
_fini(void)7567c478bd9Sstevel@tonic-gate _fini(void)
7577c478bd9Sstevel@tonic-gate {
7587c478bd9Sstevel@tonic-gate 	return (EBUSY);
7597c478bd9Sstevel@tonic-gate }
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)7627c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
7637c478bd9Sstevel@tonic-gate {
7647c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
7657c478bd9Sstevel@tonic-gate }
766