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