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