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