xref: /illumos-gate/usr/src/uts/common/fs/namefs/namevno.c (revision 134a1f4e)
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
5aa59c4cbSrsb  * Common Development and Distribution License (the "License").
6aa59c4cbSrsb  * 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 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
227c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*
26*134a1f4eSCasper H.S. Dik  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * This file defines the vnode operations for mounted file descriptors.
317c478bd9Sstevel@tonic-gate  * The routines in this file act as a layer between the NAMEFS file
327c478bd9Sstevel@tonic-gate  * system and SPECFS/FIFOFS.  With the exception of nm_open(), nm_setattr(),
337c478bd9Sstevel@tonic-gate  * nm_getattr() and nm_access(), the routines simply apply the VOP operation
347c478bd9Sstevel@tonic-gate  * to the vnode representing the file descriptor.  This switches control
357c478bd9Sstevel@tonic-gate  * to the underlying file system to which the file descriptor belongs.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate #include <sys/types.h>
387c478bd9Sstevel@tonic-gate #include <sys/param.h>
397c478bd9Sstevel@tonic-gate #include <sys/systm.h>
407c478bd9Sstevel@tonic-gate #include <sys/cred.h>
417c478bd9Sstevel@tonic-gate #include <sys/errno.h>
427c478bd9Sstevel@tonic-gate #include <sys/time.h>
437c478bd9Sstevel@tonic-gate #include <sys/file.h>
447c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
457c478bd9Sstevel@tonic-gate #include <sys/flock.h>
467c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
477c478bd9Sstevel@tonic-gate #include <sys/uio.h>
487c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
49aa59c4cbSrsb #include <sys/vfs_opreg.h>
507c478bd9Sstevel@tonic-gate #include <sys/vnode.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/proc.h>
557c478bd9Sstevel@tonic-gate #include <sys/conf.h>
567c478bd9Sstevel@tonic-gate #include <sys/debug.h>
577c478bd9Sstevel@tonic-gate #include <vm/seg.h>
587c478bd9Sstevel@tonic-gate #include <sys/fs/namenode.h>
597c478bd9Sstevel@tonic-gate #include <sys/stream.h>
607c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h>
617c478bd9Sstevel@tonic-gate #include <sys/policy.h>
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate  * Create a reference to the vnode representing the file descriptor.
657c478bd9Sstevel@tonic-gate  * Then, apply the VOP_OPEN operation to that vnode.
667c478bd9Sstevel@tonic-gate  *
677c478bd9Sstevel@tonic-gate  * The vnode for the file descriptor may be switched under you.
687c478bd9Sstevel@tonic-gate  * If it is, search the hash list for an nodep - nodep->nm_filevp
697c478bd9Sstevel@tonic-gate  * pair. If it exists, return that nodep to the user.
707c478bd9Sstevel@tonic-gate  * If it does not exist, create a new namenode to attach
717c478bd9Sstevel@tonic-gate  * to the nodep->nm_filevp then place the pair on the hash list.
727c478bd9Sstevel@tonic-gate  *
737c478bd9Sstevel@tonic-gate  * Newly created objects are like children/nodes in the mounted
747c478bd9Sstevel@tonic-gate  * file system, with the parent being the initial mount.
757c478bd9Sstevel@tonic-gate  */
767c478bd9Sstevel@tonic-gate int
77da6c28aaSamw nm_open(vnode_t **vpp, int flag, cred_t *crp, caller_context_t *ct)
787c478bd9Sstevel@tonic-gate {
797c478bd9Sstevel@tonic-gate 	struct namenode *nodep = VTONM(*vpp);
807c478bd9Sstevel@tonic-gate 	int error = 0;
817c478bd9Sstevel@tonic-gate 	struct namenode *newnamep;
827c478bd9Sstevel@tonic-gate 	struct vnode *newvp;
837c478bd9Sstevel@tonic-gate 	struct vnode *infilevp;
847c478bd9Sstevel@tonic-gate 	struct vnode *outfilevp;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 	/*
877c478bd9Sstevel@tonic-gate 	 * If the vnode is switched under us, the corresponding
887c478bd9Sstevel@tonic-gate 	 * VN_RELE for this VN_HOLD will be done by the file system
897c478bd9Sstevel@tonic-gate 	 * performing the switch. Otherwise, the corresponding
907c478bd9Sstevel@tonic-gate 	 * VN_RELE will be done by nm_close().
917c478bd9Sstevel@tonic-gate 	 */
927c478bd9Sstevel@tonic-gate 	infilevp = outfilevp = nodep->nm_filevp;
937c478bd9Sstevel@tonic-gate 	VN_HOLD(outfilevp);
947c478bd9Sstevel@tonic-gate 
95da6c28aaSamw 	if ((error = VOP_OPEN(&outfilevp, flag, crp, ct)) != 0) {
967c478bd9Sstevel@tonic-gate 		VN_RELE(outfilevp);
977c478bd9Sstevel@tonic-gate 		return (error);
987c478bd9Sstevel@tonic-gate 	}
997c478bd9Sstevel@tonic-gate 	if (infilevp != outfilevp) {
1007c478bd9Sstevel@tonic-gate 		/*
1017c478bd9Sstevel@tonic-gate 		 * See if the new filevp (outfilevp) is already associated
1027c478bd9Sstevel@tonic-gate 		 * with the mount point. If it is, then it already has a
1037c478bd9Sstevel@tonic-gate 		 * namenode associated with it.
1047c478bd9Sstevel@tonic-gate 		 */
1057c478bd9Sstevel@tonic-gate 		mutex_enter(&ntable_lock);
1067c478bd9Sstevel@tonic-gate 		if ((newnamep =
1077c478bd9Sstevel@tonic-gate 		    namefind(outfilevp, nodep->nm_mountpt)) != NULL) {
1087c478bd9Sstevel@tonic-gate 			struct vnode *vp = NMTOV(newnamep);
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 			VN_HOLD(vp);
1117c478bd9Sstevel@tonic-gate 			goto gotit;
1127c478bd9Sstevel@tonic-gate 		}
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 		newnamep = kmem_zalloc(sizeof (struct namenode), KM_SLEEP);
1157c478bd9Sstevel@tonic-gate 		newvp = vn_alloc(KM_SLEEP);
1167c478bd9Sstevel@tonic-gate 		newnamep->nm_vnode = newvp;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 		mutex_init(&newnamep->nm_lock, NULL, MUTEX_DEFAULT, NULL);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 		mutex_enter(&nodep->nm_lock);
1217c478bd9Sstevel@tonic-gate 		newvp->v_flag = ((*vpp)->v_flag | VNOMAP | VNOSWAP) & ~VROOT;
1227c478bd9Sstevel@tonic-gate 		vn_setops(newvp, vn_getops(*vpp));
1237c478bd9Sstevel@tonic-gate 		newvp->v_vfsp = &namevfs;
1247c478bd9Sstevel@tonic-gate 		newvp->v_stream = outfilevp->v_stream;
1257c478bd9Sstevel@tonic-gate 		newvp->v_type = outfilevp->v_type;
1267c478bd9Sstevel@tonic-gate 		newvp->v_rdev = outfilevp->v_rdev;
1277c478bd9Sstevel@tonic-gate 		newvp->v_data = (caddr_t)newnamep;
1287c478bd9Sstevel@tonic-gate 		vn_exists(newvp);
1297c478bd9Sstevel@tonic-gate 		bcopy(&nodep->nm_vattr, &newnamep->nm_vattr, sizeof (vattr_t));
1307c478bd9Sstevel@tonic-gate 		newnamep->nm_vattr.va_type = outfilevp->v_type;
1317c478bd9Sstevel@tonic-gate 		newnamep->nm_vattr.va_nodeid = namenodeno_alloc();
1327c478bd9Sstevel@tonic-gate 		newnamep->nm_vattr.va_size = (u_offset_t)0;
1337c478bd9Sstevel@tonic-gate 		newnamep->nm_vattr.va_rdev = outfilevp->v_rdev;
1347c478bd9Sstevel@tonic-gate 		newnamep->nm_flag = NMNMNT;
1357c478bd9Sstevel@tonic-gate 		newnamep->nm_filevp = outfilevp;
1367c478bd9Sstevel@tonic-gate 		newnamep->nm_filep = nodep->nm_filep;
1377c478bd9Sstevel@tonic-gate 		newnamep->nm_mountpt = nodep->nm_mountpt;
1387c478bd9Sstevel@tonic-gate 		mutex_exit(&nodep->nm_lock);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 		/*
1417c478bd9Sstevel@tonic-gate 		 * Insert the new namenode into the hash list.
1427c478bd9Sstevel@tonic-gate 		 */
1437c478bd9Sstevel@tonic-gate 		nameinsert(newnamep);
1447c478bd9Sstevel@tonic-gate gotit:
1457c478bd9Sstevel@tonic-gate 		mutex_exit(&ntable_lock);
1467c478bd9Sstevel@tonic-gate 		/*
1477c478bd9Sstevel@tonic-gate 		 * Release the above reference to the infilevp, the reference
1487c478bd9Sstevel@tonic-gate 		 * to the NAMEFS vnode, create a reference to the new vnode
1497c478bd9Sstevel@tonic-gate 		 * and return the new vnode to the user.
1507c478bd9Sstevel@tonic-gate 		 */
1517c478bd9Sstevel@tonic-gate 		VN_RELE(*vpp);
1527c478bd9Sstevel@tonic-gate 		*vpp = NMTOV(newnamep);
1537c478bd9Sstevel@tonic-gate 	}
1547c478bd9Sstevel@tonic-gate 	return (0);
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate /*
1587c478bd9Sstevel@tonic-gate  * Close a mounted file descriptor.
1597c478bd9Sstevel@tonic-gate  * Remove any locks and apply the VOP_CLOSE operation to the vnode for
1607c478bd9Sstevel@tonic-gate  * the file descriptor.
1617c478bd9Sstevel@tonic-gate  */
1627c478bd9Sstevel@tonic-gate static int
163da6c28aaSamw nm_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *crp,
164da6c28aaSamw 	caller_context_t *ct)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate 	struct namenode *nodep = VTONM(vp);
1677c478bd9Sstevel@tonic-gate 	int error = 0;
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	(void) cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
1707c478bd9Sstevel@tonic-gate 	cleanshares(vp, ttoproc(curthread)->p_pid);
171da6c28aaSamw 	error = VOP_CLOSE(nodep->nm_filevp, flag, count, offset, crp, ct);
1727c478bd9Sstevel@tonic-gate 	if (count == 1) {
173da6c28aaSamw 		(void) VOP_FSYNC(nodep->nm_filevp, FSYNC, crp, ct);
1747c478bd9Sstevel@tonic-gate 		/*
1757c478bd9Sstevel@tonic-gate 		 * Before VN_RELE() we need to remove the vnode from
1767c478bd9Sstevel@tonic-gate 		 * the hash table.  We should only do so in the  NMNMNT case.
1777c478bd9Sstevel@tonic-gate 		 * In other cases, nodep->nm_filep keeps a reference
1787c478bd9Sstevel@tonic-gate 		 * to nm_filevp and the entry in the hash table doesn't
1797c478bd9Sstevel@tonic-gate 		 * hurt.
1807c478bd9Sstevel@tonic-gate 		 */
1817c478bd9Sstevel@tonic-gate 		if ((nodep->nm_flag & NMNMNT) != 0) {
1827c478bd9Sstevel@tonic-gate 			mutex_enter(&ntable_lock);
1837c478bd9Sstevel@tonic-gate 			nameremove(nodep);
1847c478bd9Sstevel@tonic-gate 			mutex_exit(&ntable_lock);
1857c478bd9Sstevel@tonic-gate 		}
1867c478bd9Sstevel@tonic-gate 		VN_RELE(nodep->nm_filevp);
1877c478bd9Sstevel@tonic-gate 	}
1887c478bd9Sstevel@tonic-gate 	return (error);
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate static int
1927c478bd9Sstevel@tonic-gate nm_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *crp,
1937c478bd9Sstevel@tonic-gate 	caller_context_t *ct)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate 	return (VOP_READ(VTONM(vp)->nm_filevp, uiop, ioflag, crp, ct));
1967c478bd9Sstevel@tonic-gate }
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate static int
1997c478bd9Sstevel@tonic-gate nm_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *crp,
2007c478bd9Sstevel@tonic-gate 	caller_context_t *ct)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate 	return (VOP_WRITE(VTONM(vp)->nm_filevp, uiop, ioflag, crp, ct));
2037c478bd9Sstevel@tonic-gate }
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate static int
206da6c28aaSamw nm_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode, cred_t *cr, int *rvalp,
207da6c28aaSamw 	caller_context_t *ct)
2087c478bd9Sstevel@tonic-gate {
209da6c28aaSamw 	return (VOP_IOCTL(VTONM(vp)->nm_filevp, cmd, arg, mode, cr, rvalp, ct));
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate  * Return in vap the attributes that are stored in the namenode
2147c478bd9Sstevel@tonic-gate  * structure.  Only the size is taken from the mounted object.
2157c478bd9Sstevel@tonic-gate  */
2167c478bd9Sstevel@tonic-gate /* ARGSUSED */
2177c478bd9Sstevel@tonic-gate static int
218da6c28aaSamw nm_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp,
219da6c28aaSamw 	caller_context_t *ct)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate 	struct namenode *nodep = VTONM(vp);
2227c478bd9Sstevel@tonic-gate 	struct vattr va;
2237c478bd9Sstevel@tonic-gate 	int error;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	mutex_enter(&nodep->nm_lock);
2267c478bd9Sstevel@tonic-gate 	bcopy(&nodep->nm_vattr, vap, sizeof (vattr_t));
2277c478bd9Sstevel@tonic-gate 	mutex_exit(&nodep->nm_lock);
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	if ((va.va_mask = vap->va_mask & AT_SIZE) != 0) {
230da6c28aaSamw 		if (error = VOP_GETATTR(nodep->nm_filevp, &va, flags, crp, ct))
2317c478bd9Sstevel@tonic-gate 			return (error);
2327c478bd9Sstevel@tonic-gate 		vap->va_size = va.va_size;
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	return (0);
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate /*
2397c478bd9Sstevel@tonic-gate  * Standard access() like check.  Figure out which mode bits apply
2407c478bd9Sstevel@tonic-gate  * to the caller then pass the missing mode bits to the secpolicy function.
2417c478bd9Sstevel@tonic-gate  */
2427c478bd9Sstevel@tonic-gate static int
2437c478bd9Sstevel@tonic-gate nm_access_unlocked(void *vnp, int mode, cred_t *crp)
2447c478bd9Sstevel@tonic-gate {
2457c478bd9Sstevel@tonic-gate 	struct namenode *nodep = vnp;
2467c478bd9Sstevel@tonic-gate 	int shift = 0;
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	if (crgetuid(crp) != nodep->nm_vattr.va_uid) {
2497c478bd9Sstevel@tonic-gate 		shift += 3;
2507c478bd9Sstevel@tonic-gate 		if (!groupmember(nodep->nm_vattr.va_gid, crp))
2517c478bd9Sstevel@tonic-gate 			shift += 3;
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 
254*134a1f4eSCasper H.S. Dik 	return (secpolicy_vnode_access2(crp, NMTOV(nodep),
255*134a1f4eSCasper H.S. Dik 	    nodep->nm_vattr.va_uid, nodep->nm_vattr.va_mode << shift,
256*134a1f4eSCasper H.S. Dik 	    mode));
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate /*
2597c478bd9Sstevel@tonic-gate  * Set the attributes of the namenode from the attributes in vap.
2607c478bd9Sstevel@tonic-gate  */
2617c478bd9Sstevel@tonic-gate /* ARGSUSED */
2627c478bd9Sstevel@tonic-gate static int
2637c478bd9Sstevel@tonic-gate nm_setattr(
2647c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2657c478bd9Sstevel@tonic-gate 	vattr_t *vap,
2667c478bd9Sstevel@tonic-gate 	int flags,
2677c478bd9Sstevel@tonic-gate 	cred_t *crp,
2687c478bd9Sstevel@tonic-gate 	caller_context_t *ctp)
2697c478bd9Sstevel@tonic-gate {
2707c478bd9Sstevel@tonic-gate 	struct namenode *nodep = VTONM(vp);
2717c478bd9Sstevel@tonic-gate 	struct vattr *nmvap = &nodep->nm_vattr;
2727c478bd9Sstevel@tonic-gate 	long mask = vap->va_mask;
2737c478bd9Sstevel@tonic-gate 	int error = 0;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	/*
2767c478bd9Sstevel@tonic-gate 	 * Cannot set these attributes.
2777c478bd9Sstevel@tonic-gate 	 */
2787c478bd9Sstevel@tonic-gate 	if (mask & (AT_NOSET|AT_SIZE))
2797c478bd9Sstevel@tonic-gate 		return (EINVAL);
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	(void) VOP_RWLOCK(nodep->nm_filevp, V_WRITELOCK_TRUE, ctp);
2827c478bd9Sstevel@tonic-gate 	mutex_enter(&nodep->nm_lock);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	/*
2857c478bd9Sstevel@tonic-gate 	 * Change ownership/group/time/access mode of mounted file
2867c478bd9Sstevel@tonic-gate 	 * descriptor.
2877c478bd9Sstevel@tonic-gate 	 */
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	error = secpolicy_vnode_setattr(crp, vp, vap, nmvap, flags,
2908c819381Spf 	    nm_access_unlocked, nodep);
2917c478bd9Sstevel@tonic-gate 	if (error)
2927c478bd9Sstevel@tonic-gate 		goto out;
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	mask = vap->va_mask;
2957c478bd9Sstevel@tonic-gate 	/*
2967c478bd9Sstevel@tonic-gate 	 * If request to change mode, copy new
2977c478bd9Sstevel@tonic-gate 	 * mode into existing attribute structure.
2987c478bd9Sstevel@tonic-gate 	 */
2997c478bd9Sstevel@tonic-gate 	if (mask & AT_MODE)
3007c478bd9Sstevel@tonic-gate 		nmvap->va_mode = vap->va_mode & ~VSVTX;
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	/*
3037c478bd9Sstevel@tonic-gate 	 * If request was to change user or group, turn off suid and sgid
3047c478bd9Sstevel@tonic-gate 	 * bits.
3057c478bd9Sstevel@tonic-gate 	 * If the system was configured with the "rstchown" option, the
3067c478bd9Sstevel@tonic-gate 	 * owner is not permitted to give away the file, and can change
3077c478bd9Sstevel@tonic-gate 	 * the group id only to a group of which he or she is a member.
3087c478bd9Sstevel@tonic-gate 	 */
3097c478bd9Sstevel@tonic-gate 	if (mask & AT_UID)
3107c478bd9Sstevel@tonic-gate 		nmvap->va_uid = vap->va_uid;
3117c478bd9Sstevel@tonic-gate 	if (mask & AT_GID)
3127c478bd9Sstevel@tonic-gate 		nmvap->va_gid = vap->va_gid;
3137c478bd9Sstevel@tonic-gate 	/*
3147c478bd9Sstevel@tonic-gate 	 * If request is to modify times, make sure user has write
3157c478bd9Sstevel@tonic-gate 	 * permissions on the file.
3167c478bd9Sstevel@tonic-gate 	 */
3177c478bd9Sstevel@tonic-gate 	if (mask & AT_ATIME)
3187c478bd9Sstevel@tonic-gate 		nmvap->va_atime = vap->va_atime;
3197c478bd9Sstevel@tonic-gate 	if (mask & AT_MTIME) {
3207c478bd9Sstevel@tonic-gate 		nmvap->va_mtime = vap->va_mtime;
3217c478bd9Sstevel@tonic-gate 		gethrestime(&nmvap->va_ctime);
3227c478bd9Sstevel@tonic-gate 	}
3237c478bd9Sstevel@tonic-gate out:
3247c478bd9Sstevel@tonic-gate 	mutex_exit(&nodep->nm_lock);
3257c478bd9Sstevel@tonic-gate 	VOP_RWUNLOCK(nodep->nm_filevp, V_WRITELOCK_TRUE, ctp);
3267c478bd9Sstevel@tonic-gate 	return (error);
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate /*
3307c478bd9Sstevel@tonic-gate  * Check mode permission on the namenode.  First nm_access_unlocked()
3317c478bd9Sstevel@tonic-gate  * checks the bits on the name node, then an access check is performed
3327c478bd9Sstevel@tonic-gate  * on the underlying file.
3337c478bd9Sstevel@tonic-gate  */
3347c478bd9Sstevel@tonic-gate /* ARGSUSED */
3357c478bd9Sstevel@tonic-gate static int
336da6c28aaSamw nm_access(vnode_t *vp, int mode, int flags, cred_t *crp,
337da6c28aaSamw 	caller_context_t *ct)
3387c478bd9Sstevel@tonic-gate {
3397c478bd9Sstevel@tonic-gate 	struct namenode *nodep = VTONM(vp);
3407c478bd9Sstevel@tonic-gate 	int error;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	mutex_enter(&nodep->nm_lock);
3437c478bd9Sstevel@tonic-gate 	error = nm_access_unlocked(nodep, mode, crp);
3447c478bd9Sstevel@tonic-gate 	mutex_exit(&nodep->nm_lock);
3457c478bd9Sstevel@tonic-gate 	if (error == 0)
346da6c28aaSamw 		return (VOP_ACCESS(nodep->nm_filevp, mode, flags, crp, ct));
3477c478bd9Sstevel@tonic-gate 	else
3487c478bd9Sstevel@tonic-gate 		return (error);
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate /*
3527c478bd9Sstevel@tonic-gate  * We can get here if a creat or open with O_CREAT is done on a namefs
3537c478bd9Sstevel@tonic-gate  * mount point, for example, as the object of a shell output redirection to
3547c478bd9Sstevel@tonic-gate  * the mount point.
3557c478bd9Sstevel@tonic-gate  */
3567c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3577c478bd9Sstevel@tonic-gate static int
3587c478bd9Sstevel@tonic-gate nm_create(vnode_t *dvp, char *name, vattr_t *vap, enum vcexcl excl,
359da6c28aaSamw 	int mode, vnode_t **vpp, cred_t *cr, int flag,
360da6c28aaSamw 	caller_context_t *ct, vsecattr_t *vsecp)
3617c478bd9Sstevel@tonic-gate {
3627c478bd9Sstevel@tonic-gate 	int error;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	ASSERT(dvp && *name == '\0');
3657c478bd9Sstevel@tonic-gate 	if (excl == NONEXCL) {
366da6c28aaSamw 		if (mode && (error = nm_access(dvp, mode, 0, cr, ct)) != 0)
3677c478bd9Sstevel@tonic-gate 			return (error);
3687c478bd9Sstevel@tonic-gate 		VN_HOLD(dvp);
3697c478bd9Sstevel@tonic-gate 		return (0);
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 	return (EEXIST);
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate /*
3757c478bd9Sstevel@tonic-gate  * Links are not allowed on mounted file descriptors.
3767c478bd9Sstevel@tonic-gate  */
3777c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3787c478bd9Sstevel@tonic-gate static int
379da6c28aaSamw nm_link(vnode_t *tdvp, vnode_t *vp, char *tnm, cred_t *crp,
380da6c28aaSamw 	caller_context_t *ct, int flags)
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate 	return (EXDEV);
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate static int
386da6c28aaSamw nm_fsync(vnode_t *vp, int syncflag, cred_t *crp, caller_context_t *ct)
3877c478bd9Sstevel@tonic-gate {
388da6c28aaSamw 	return (VOP_FSYNC(VTONM(vp)->nm_filevp, syncflag, crp, ct));
3897c478bd9Sstevel@tonic-gate }
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate /* Free the namenode */
3927c478bd9Sstevel@tonic-gate /* ARGSUSED */
3937c478bd9Sstevel@tonic-gate static void
394da6c28aaSamw nm_inactive(vnode_t *vp, cred_t *crp, caller_context_t *ct)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate 	struct namenode *nodep = VTONM(vp);
3978c819381Spf 	vfs_t *vfsp = vp->v_vfsp;
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
4007c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_count >= 1);
4017c478bd9Sstevel@tonic-gate 	if (--vp->v_count != 0) {
4027c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
4037c478bd9Sstevel@tonic-gate 		return;
4047c478bd9Sstevel@tonic-gate 	}
4057c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
4067c478bd9Sstevel@tonic-gate 	if (!(nodep->nm_flag & NMNMNT)) {
4077c478bd9Sstevel@tonic-gate 		ASSERT(nodep->nm_filep->f_vnode == nodep->nm_filevp);
4087c478bd9Sstevel@tonic-gate 		(void) closef(nodep->nm_filep);
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 	vn_invalid(vp);
4117c478bd9Sstevel@tonic-gate 	vn_free(vp);
4128c819381Spf 	if (vfsp != &namevfs)
4138c819381Spf 		VFS_RELE(vfsp);
4147c478bd9Sstevel@tonic-gate 	namenodeno_free(nodep->nm_vattr.va_nodeid);
4157c478bd9Sstevel@tonic-gate 	kmem_free(nodep, sizeof (struct namenode));
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate static int
419da6c28aaSamw nm_fid(vnode_t *vp, struct fid *fidnodep, caller_context_t *ct)
4207c478bd9Sstevel@tonic-gate {
421da6c28aaSamw 	return (VOP_FID(VTONM(vp)->nm_filevp, fidnodep, ct));
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate static int
4257c478bd9Sstevel@tonic-gate nm_rwlock(vnode_t *vp, int write, caller_context_t *ctp)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate 	return (VOP_RWLOCK(VTONM(vp)->nm_filevp, write, ctp));
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate static void
4317c478bd9Sstevel@tonic-gate nm_rwunlock(vnode_t *vp, int write, caller_context_t *ctp)
4327c478bd9Sstevel@tonic-gate {
4337c478bd9Sstevel@tonic-gate 	VOP_RWUNLOCK(VTONM(vp)->nm_filevp, write, ctp);
4347c478bd9Sstevel@tonic-gate }
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate static int
437da6c28aaSamw nm_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
4387c478bd9Sstevel@tonic-gate {
439da6c28aaSamw 	return (VOP_SEEK(VTONM(vp)->nm_filevp, ooff, noffp, ct));
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate /*
4437c478bd9Sstevel@tonic-gate  * Return the vnode representing the file descriptor in vpp.
4447c478bd9Sstevel@tonic-gate  */
4457c478bd9Sstevel@tonic-gate static int
446da6c28aaSamw nm_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
4477c478bd9Sstevel@tonic-gate {
4487c478bd9Sstevel@tonic-gate 	struct vnode *rvp;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	vp = VTONM(vp)->nm_filevp;
451da6c28aaSamw 	if (VOP_REALVP(vp, &rvp, ct) == 0)
4527c478bd9Sstevel@tonic-gate 		vp = rvp;
4537c478bd9Sstevel@tonic-gate 	*vpp = vp;
4547c478bd9Sstevel@tonic-gate 	return (0);
4557c478bd9Sstevel@tonic-gate }
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate static int
4587c478bd9Sstevel@tonic-gate nm_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
459da6c28aaSamw 	pollhead_t **phpp, caller_context_t *ct)
4607c478bd9Sstevel@tonic-gate {
461da6c28aaSamw 	return (VOP_POLL(VTONM(vp)->nm_filevp, events, anyyet, reventsp,
462da6c28aaSamw 	    phpp, ct));
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate struct vnodeops *nm_vnodeops;
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate const fs_operation_def_t nm_vnodeops_template[] = {
468aa59c4cbSrsb 	VOPNAME_OPEN,		{ .vop_open = nm_open },
469aa59c4cbSrsb 	VOPNAME_CLOSE,		{ .vop_close = nm_close },
470aa59c4cbSrsb 	VOPNAME_READ,		{ .vop_read = nm_read },
471aa59c4cbSrsb 	VOPNAME_WRITE,		{ .vop_write = nm_write },
472aa59c4cbSrsb 	VOPNAME_IOCTL,		{ .vop_ioctl = nm_ioctl },
473aa59c4cbSrsb 	VOPNAME_GETATTR,	{ .vop_getattr = nm_getattr },
474aa59c4cbSrsb 	VOPNAME_SETATTR,	{ .vop_setattr = nm_setattr },
475aa59c4cbSrsb 	VOPNAME_ACCESS,		{ .vop_access = nm_access },
476aa59c4cbSrsb 	VOPNAME_CREATE,		{ .vop_create = nm_create },
477aa59c4cbSrsb 	VOPNAME_LINK,		{ .vop_link = nm_link },
478aa59c4cbSrsb 	VOPNAME_FSYNC,		{ .vop_fsync = nm_fsync },
479aa59c4cbSrsb 	VOPNAME_INACTIVE,	{ .vop_inactive = nm_inactive },
480aa59c4cbSrsb 	VOPNAME_FID,		{ .vop_fid = nm_fid },
481aa59c4cbSrsb 	VOPNAME_RWLOCK,		{ .vop_rwlock = nm_rwlock },
482aa59c4cbSrsb 	VOPNAME_RWUNLOCK,	{ .vop_rwunlock = nm_rwunlock },
483aa59c4cbSrsb 	VOPNAME_SEEK,		{ .vop_seek = nm_seek },
484aa59c4cbSrsb 	VOPNAME_REALVP,		{ .vop_realvp = nm_realvp },
485aa59c4cbSrsb 	VOPNAME_POLL,		{ .vop_poll = nm_poll },
486aa59c4cbSrsb 	VOPNAME_DISPOSE,	{ .error = fs_error },
487aa59c4cbSrsb 	NULL,			NULL
4887c478bd9Sstevel@tonic-gate };
489