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, 2907c478bd9Sstevel@tonic-gate 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); 3978c819381Spf199842 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); 4128c819381Spf199842 if (vfsp != &namevfs) 4138c819381Spf199842 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 }, 4877c478bd9Sstevel@tonic-gate NULL, NULL 4887c478bd9Sstevel@tonic-gate }; 489