xref: /illumos-gate/usr/src/uts/common/fs/namefs/namevno.c (revision ade42b55)
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*ade42b55SSebastien Roy  * Copyright (c) 2016, 2017 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
nm_open(vnode_t ** vpp,int flag,cred_t * crp,caller_context_t * ct)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
nm_close(vnode_t * vp,int flag,int count,offset_t offset,cred_t * crp,caller_context_t * ct)164da6c28aaSamw nm_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *crp,
165*ade42b55SSebastien Roy     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
nm_read(vnode_t * vp,struct uio * uiop,int ioflag,cred_t * crp,caller_context_t * ct)1937c478bd9Sstevel@tonic-gate nm_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *crp,
194*ade42b55SSebastien Roy     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
nm_write(vnode_t * vp,struct uio * uiop,int ioflag,cred_t * crp,caller_context_t * ct)2007c478bd9Sstevel@tonic-gate nm_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *crp,
201*ade42b55SSebastien Roy     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
nm_ioctl(vnode_t * vp,int cmd,intptr_t arg,int mode,cred_t * cr,int * rvalp,caller_context_t * ct)207da6c28aaSamw nm_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode, cred_t *cr, int *rvalp,
208*ade42b55SSebastien Roy     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
nm_getattr(vnode_t * vp,vattr_t * vap,int flags,cred_t * crp,caller_context_t * ct)219da6c28aaSamw nm_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp,
220*ade42b55SSebastien Roy     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
nm_access_unlocked(void * vnp,int mode,cred_t * crp)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
nm_setattr(vnode_t * vp,vattr_t * vap,int flags,cred_t * crp,caller_context_t * ctp)264*ade42b55SSebastien Roy nm_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp,
265*ade42b55SSebastien Roy     caller_context_t *ctp)
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate 	struct namenode *nodep = VTONM(vp);
2687c478bd9Sstevel@tonic-gate 	struct vattr *nmvap = &nodep->nm_vattr;
2697c478bd9Sstevel@tonic-gate 	long mask = vap->va_mask;
2707c478bd9Sstevel@tonic-gate 	int error = 0;
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	/*
2737c478bd9Sstevel@tonic-gate 	 * Cannot set these attributes.
2747c478bd9Sstevel@tonic-gate 	 */
2757c478bd9Sstevel@tonic-gate 	if (mask & (AT_NOSET|AT_SIZE))
2767c478bd9Sstevel@tonic-gate 		return (EINVAL);
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	(void) VOP_RWLOCK(nodep->nm_filevp, V_WRITELOCK_TRUE, ctp);
2797c478bd9Sstevel@tonic-gate 	mutex_enter(&nodep->nm_lock);
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	/*
2827c478bd9Sstevel@tonic-gate 	 * Change ownership/group/time/access mode of mounted file
2837c478bd9Sstevel@tonic-gate 	 * descriptor.
2847c478bd9Sstevel@tonic-gate 	 */
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	error = secpolicy_vnode_setattr(crp, vp, vap, nmvap, flags,
2878c819381Spf 	    nm_access_unlocked, nodep);
2887c478bd9Sstevel@tonic-gate 	if (error)
2897c478bd9Sstevel@tonic-gate 		goto out;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	mask = vap->va_mask;
2927c478bd9Sstevel@tonic-gate 	/*
2937c478bd9Sstevel@tonic-gate 	 * If request to change mode, copy new
2947c478bd9Sstevel@tonic-gate 	 * mode into existing attribute structure.
2957c478bd9Sstevel@tonic-gate 	 */
2967c478bd9Sstevel@tonic-gate 	if (mask & AT_MODE)
2977c478bd9Sstevel@tonic-gate 		nmvap->va_mode = vap->va_mode & ~VSVTX;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	/*
3007c478bd9Sstevel@tonic-gate 	 * If request was to change user or group, turn off suid and sgid
3017c478bd9Sstevel@tonic-gate 	 * bits.
3027c478bd9Sstevel@tonic-gate 	 * If the system was configured with the "rstchown" option, the
3037c478bd9Sstevel@tonic-gate 	 * owner is not permitted to give away the file, and can change
30448bbca81SDaniel Hoffman 	 * the group id only to a group of which they are a member.
3057c478bd9Sstevel@tonic-gate 	 */
3067c478bd9Sstevel@tonic-gate 	if (mask & AT_UID)
3077c478bd9Sstevel@tonic-gate 		nmvap->va_uid = vap->va_uid;
3087c478bd9Sstevel@tonic-gate 	if (mask & AT_GID)
3097c478bd9Sstevel@tonic-gate 		nmvap->va_gid = vap->va_gid;
3107c478bd9Sstevel@tonic-gate 	/*
3117c478bd9Sstevel@tonic-gate 	 * If request is to modify times, make sure user has write
3127c478bd9Sstevel@tonic-gate 	 * permissions on the file.
3137c478bd9Sstevel@tonic-gate 	 */
3147c478bd9Sstevel@tonic-gate 	if (mask & AT_ATIME)
3157c478bd9Sstevel@tonic-gate 		nmvap->va_atime = vap->va_atime;
3167c478bd9Sstevel@tonic-gate 	if (mask & AT_MTIME) {
3177c478bd9Sstevel@tonic-gate 		nmvap->va_mtime = vap->va_mtime;
3187c478bd9Sstevel@tonic-gate 		gethrestime(&nmvap->va_ctime);
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate out:
3217c478bd9Sstevel@tonic-gate 	mutex_exit(&nodep->nm_lock);
3227c478bd9Sstevel@tonic-gate 	VOP_RWUNLOCK(nodep->nm_filevp, V_WRITELOCK_TRUE, ctp);
3237c478bd9Sstevel@tonic-gate 	return (error);
3247c478bd9Sstevel@tonic-gate }
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate /*
3277c478bd9Sstevel@tonic-gate  * Check mode permission on the namenode.  First nm_access_unlocked()
3287c478bd9Sstevel@tonic-gate  * checks the bits on the name node, then an access check is performed
3297c478bd9Sstevel@tonic-gate  * on the underlying file.
3307c478bd9Sstevel@tonic-gate  */
3317c478bd9Sstevel@tonic-gate /* ARGSUSED */
3327c478bd9Sstevel@tonic-gate static int
nm_access(vnode_t * vp,int mode,int flags,cred_t * crp,caller_context_t * ct)333*ade42b55SSebastien Roy nm_access(vnode_t *vp, int mode, int flags, cred_t *crp, caller_context_t *ct)
3347c478bd9Sstevel@tonic-gate {
3357c478bd9Sstevel@tonic-gate 	struct namenode *nodep = VTONM(vp);
3367c478bd9Sstevel@tonic-gate 	int error;
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	mutex_enter(&nodep->nm_lock);
3397c478bd9Sstevel@tonic-gate 	error = nm_access_unlocked(nodep, mode, crp);
3407c478bd9Sstevel@tonic-gate 	mutex_exit(&nodep->nm_lock);
3417c478bd9Sstevel@tonic-gate 	if (error == 0)
342da6c28aaSamw 		return (VOP_ACCESS(nodep->nm_filevp, mode, flags, crp, ct));
3437c478bd9Sstevel@tonic-gate 	else
3447c478bd9Sstevel@tonic-gate 		return (error);
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate /*
3487c478bd9Sstevel@tonic-gate  * We can get here if a creat or open with O_CREAT is done on a namefs
3497c478bd9Sstevel@tonic-gate  * mount point, for example, as the object of a shell output redirection to
3507c478bd9Sstevel@tonic-gate  * the mount point.
3517c478bd9Sstevel@tonic-gate  */
3527c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3537c478bd9Sstevel@tonic-gate static int
nm_create(vnode_t * dvp,char * name,vattr_t * vap,enum vcexcl excl,int mode,vnode_t ** vpp,cred_t * cr,int flag,caller_context_t * ct,vsecattr_t * vsecp)354*ade42b55SSebastien Roy nm_create(vnode_t *dvp, char *name, vattr_t *vap, enum vcexcl excl, int mode,
355*ade42b55SSebastien Roy     vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
356*ade42b55SSebastien Roy     vsecattr_t *vsecp)
3577c478bd9Sstevel@tonic-gate {
3587c478bd9Sstevel@tonic-gate 	int error;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	ASSERT(dvp && *name == '\0');
3617c478bd9Sstevel@tonic-gate 	if (excl == NONEXCL) {
362da6c28aaSamw 		if (mode && (error = nm_access(dvp, mode, 0, cr, ct)) != 0)
3637c478bd9Sstevel@tonic-gate 			return (error);
3647c478bd9Sstevel@tonic-gate 		VN_HOLD(dvp);
3657c478bd9Sstevel@tonic-gate 		return (0);
3667c478bd9Sstevel@tonic-gate 	}
3677c478bd9Sstevel@tonic-gate 	return (EEXIST);
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate /*
3717c478bd9Sstevel@tonic-gate  * Links are not allowed on mounted file descriptors.
3727c478bd9Sstevel@tonic-gate  */
3737c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3747c478bd9Sstevel@tonic-gate static int
nm_link(vnode_t * tdvp,vnode_t * vp,char * tnm,cred_t * crp,caller_context_t * ct,int flags)375da6c28aaSamw nm_link(vnode_t *tdvp, vnode_t *vp, char *tnm, cred_t *crp,
376*ade42b55SSebastien Roy     caller_context_t *ct, int flags)
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate 	return (EXDEV);
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate static int
nm_fsync(vnode_t * vp,int syncflag,cred_t * crp,caller_context_t * ct)382da6c28aaSamw nm_fsync(vnode_t *vp, int syncflag, cred_t *crp, caller_context_t *ct)
3837c478bd9Sstevel@tonic-gate {
384da6c28aaSamw 	return (VOP_FSYNC(VTONM(vp)->nm_filevp, syncflag, crp, ct));
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate /* Free the namenode */
3887c478bd9Sstevel@tonic-gate /* ARGSUSED */
3897c478bd9Sstevel@tonic-gate static void
nm_inactive(vnode_t * vp,cred_t * crp,caller_context_t * ct)390da6c28aaSamw nm_inactive(vnode_t *vp, cred_t *crp, caller_context_t *ct)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate 	struct namenode *nodep = VTONM(vp);
3938c819381Spf 	vfs_t *vfsp = vp->v_vfsp;
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
3967c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_count >= 1);
397*ade42b55SSebastien Roy 	VN_RELE_LOCKED(vp);
398*ade42b55SSebastien Roy 	if (vp->v_count != 0) {
3997c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
4007c478bd9Sstevel@tonic-gate 		return;
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
4037c478bd9Sstevel@tonic-gate 	if (!(nodep->nm_flag & NMNMNT)) {
4047c478bd9Sstevel@tonic-gate 		ASSERT(nodep->nm_filep->f_vnode == nodep->nm_filevp);
4057c478bd9Sstevel@tonic-gate 		(void) closef(nodep->nm_filep);
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate 	vn_invalid(vp);
4087c478bd9Sstevel@tonic-gate 	vn_free(vp);
4098c819381Spf 	if (vfsp != &namevfs)
4108c819381Spf 		VFS_RELE(vfsp);
4117c478bd9Sstevel@tonic-gate 	namenodeno_free(nodep->nm_vattr.va_nodeid);
4127c478bd9Sstevel@tonic-gate 	kmem_free(nodep, sizeof (struct namenode));
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate static int
nm_fid(vnode_t * vp,struct fid * fidnodep,caller_context_t * ct)416da6c28aaSamw nm_fid(vnode_t *vp, struct fid *fidnodep, caller_context_t *ct)
4177c478bd9Sstevel@tonic-gate {
418da6c28aaSamw 	return (VOP_FID(VTONM(vp)->nm_filevp, fidnodep, ct));
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate static int
nm_rwlock(vnode_t * vp,int write,caller_context_t * ctp)4227c478bd9Sstevel@tonic-gate nm_rwlock(vnode_t *vp, int write, caller_context_t *ctp)
4237c478bd9Sstevel@tonic-gate {
4247c478bd9Sstevel@tonic-gate 	return (VOP_RWLOCK(VTONM(vp)->nm_filevp, write, ctp));
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate static void
nm_rwunlock(vnode_t * vp,int write,caller_context_t * ctp)4287c478bd9Sstevel@tonic-gate nm_rwunlock(vnode_t *vp, int write, caller_context_t *ctp)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate 	VOP_RWUNLOCK(VTONM(vp)->nm_filevp, write, ctp);
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate static int
nm_seek(vnode_t * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)434da6c28aaSamw nm_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
4357c478bd9Sstevel@tonic-gate {
436da6c28aaSamw 	return (VOP_SEEK(VTONM(vp)->nm_filevp, ooff, noffp, ct));
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate /*
4407c478bd9Sstevel@tonic-gate  * Return the vnode representing the file descriptor in vpp.
4417c478bd9Sstevel@tonic-gate  */
4427c478bd9Sstevel@tonic-gate static int
nm_realvp(vnode_t * vp,vnode_t ** vpp,caller_context_t * ct)443da6c28aaSamw nm_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate 	struct vnode *rvp;
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	vp = VTONM(vp)->nm_filevp;
448da6c28aaSamw 	if (VOP_REALVP(vp, &rvp, ct) == 0)
4497c478bd9Sstevel@tonic-gate 		vp = rvp;
4507c478bd9Sstevel@tonic-gate 	*vpp = vp;
4517c478bd9Sstevel@tonic-gate 	return (0);
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate static int
nm_poll(vnode_t * vp,short events,int anyyet,short * reventsp,pollhead_t ** phpp,caller_context_t * ct)4557c478bd9Sstevel@tonic-gate nm_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
456*ade42b55SSebastien Roy     pollhead_t **phpp, caller_context_t *ct)
4577c478bd9Sstevel@tonic-gate {
458da6c28aaSamw 	return (VOP_POLL(VTONM(vp)->nm_filevp, events, anyyet, reventsp,
459da6c28aaSamw 	    phpp, ct));
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate struct vnodeops *nm_vnodeops;
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate const fs_operation_def_t nm_vnodeops_template[] = {
465aa59c4cbSrsb 	VOPNAME_OPEN,		{ .vop_open = nm_open },
466aa59c4cbSrsb 	VOPNAME_CLOSE,		{ .vop_close = nm_close },
467aa59c4cbSrsb 	VOPNAME_READ,		{ .vop_read = nm_read },
468aa59c4cbSrsb 	VOPNAME_WRITE,		{ .vop_write = nm_write },
469aa59c4cbSrsb 	VOPNAME_IOCTL,		{ .vop_ioctl = nm_ioctl },
470aa59c4cbSrsb 	VOPNAME_GETATTR,	{ .vop_getattr = nm_getattr },
471aa59c4cbSrsb 	VOPNAME_SETATTR,	{ .vop_setattr = nm_setattr },
472aa59c4cbSrsb 	VOPNAME_ACCESS,		{ .vop_access = nm_access },
473aa59c4cbSrsb 	VOPNAME_CREATE,		{ .vop_create = nm_create },
474aa59c4cbSrsb 	VOPNAME_LINK,		{ .vop_link = nm_link },
475aa59c4cbSrsb 	VOPNAME_FSYNC,		{ .vop_fsync = nm_fsync },
476aa59c4cbSrsb 	VOPNAME_INACTIVE,	{ .vop_inactive = nm_inactive },
477aa59c4cbSrsb 	VOPNAME_FID,		{ .vop_fid = nm_fid },
478aa59c4cbSrsb 	VOPNAME_RWLOCK,		{ .vop_rwlock = nm_rwlock },
479aa59c4cbSrsb 	VOPNAME_RWUNLOCK,	{ .vop_rwunlock = nm_rwunlock },
480aa59c4cbSrsb 	VOPNAME_SEEK,		{ .vop_seek = nm_seek },
481aa59c4cbSrsb 	VOPNAME_REALVP,		{ .vop_realvp = nm_realvp },
482aa59c4cbSrsb 	VOPNAME_POLL,		{ .vop_poll = nm_poll },
483aa59c4cbSrsb 	VOPNAME_DISPOSE,	{ .error = fs_error },
484aa59c4cbSrsb 	NULL,			NULL
4857c478bd9Sstevel@tonic-gate };
486