1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/vnode.h> 31 #include <sys/door.h> 32 #include <sys/proc.h> 33 #include <sys/kmem.h> 34 #include <sys/debug.h> 35 #include <sys/cmn_err.h> 36 #include <fs/fs_subr.h> 37 38 39 kmutex_t door_knob; 40 static int door_open(struct vnode **vpp, int flag, struct cred *cr); 41 static int door_close(struct vnode *vp, int flag, int count, 42 offset_t offset, struct cred *cr); 43 static int door_getattr(struct vnode *vp, struct vattr *vap, 44 int flags, struct cred *cr); 45 static void door_inactive(struct vnode *vp, struct cred *cr); 46 static int door_access(struct vnode *vp, int mode, int flags, 47 struct cred *cr); 48 static int door_realvp(vnode_t *vp, vnode_t **vpp); 49 50 struct vfs door_vfs; 51 52 struct vnodeops *door_vnodeops; 53 54 const fs_operation_def_t door_vnodeops_template[] = { 55 VOPNAME_OPEN, door_open, 56 VOPNAME_CLOSE, door_close, 57 VOPNAME_GETATTR, door_getattr, 58 VOPNAME_ACCESS, door_access, 59 VOPNAME_INACTIVE, (fs_generic_func_p) door_inactive, 60 VOPNAME_FRLOCK, fs_error, 61 VOPNAME_REALVP, door_realvp, 62 VOPNAME_POLL, fs_error, 63 VOPNAME_PATHCONF, fs_error, 64 VOPNAME_DISPOSE, fs_error, 65 VOPNAME_GETSECATTR, fs_error, 66 VOPNAME_SHRLOCK, fs_error, 67 NULL, NULL 68 }; 69 70 /* ARGSUSED */ 71 static int 72 door_open(struct vnode **vpp, int flag, struct cred *cr) 73 { 74 return (0); 75 } 76 77 /* ARGSUSED */ 78 static int 79 door_close( 80 struct vnode *vp, 81 int flag, 82 int count, 83 offset_t offset, 84 struct cred *cr 85 ) 86 { 87 door_node_t *dp = VTOD(vp); 88 89 /* 90 * If this is being called from closeall on exit, any doors created 91 * by this process should have been revoked already in door_exit. 92 */ 93 ASSERT(dp->door_target != curproc || 94 ((curthread->t_proc_flag & TP_LWPEXIT) == 0)); 95 96 /* 97 * Deliver an unref if needed. 98 * 99 * If the count is equal to 2, it means that I'm doing a VOP_CLOSE 100 * on the next to last reference for *this* file struct. There may 101 * be multiple files pointing to this vnode in which case the v_count 102 * will be > 1. 103 * 104 * The door_active count is bumped during each invocation. 105 */ 106 if (count == 2 && vp->v_count == 1 && 107 (dp->door_flags & (DOOR_UNREF | DOOR_UNREF_MULTI))) { 108 mutex_enter(&door_knob); 109 if (dp->door_active == 0) { 110 /* o.k. to deliver unref now */ 111 door_deliver_unref(dp); 112 } else { 113 /* do the unref later */ 114 dp->door_flags |= DOOR_DELAY; 115 } 116 mutex_exit(&door_knob); 117 } 118 return (0); 119 } 120 121 /* ARGSUSED */ 122 static int 123 door_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr) 124 { 125 static timestruc_t tzero = {0, 0}; 126 extern dev_t doordev; 127 128 vap->va_mask = 0; /* bit-mask of attributes */ 129 vap->va_type = vp->v_type; /* vnode type (for create) */ 130 vap->va_mode = 0777; /* file access mode */ 131 vap->va_uid = 0; /* owner user id */ 132 vap->va_gid = 0; /* owner group id */ 133 vap->va_fsid = doordev; /* file system id (dev for now) */ 134 vap->va_nodeid = (ino64_t)0; /* node id */ 135 vap->va_nlink = vp->v_count; /* number of references to file */ 136 vap->va_size = (u_offset_t)0; /* file size in bytes */ 137 vap->va_atime = tzero; /* time of last access */ 138 vap->va_mtime = tzero; /* time of last modification */ 139 vap->va_ctime = tzero; /* time file ``created'' */ 140 vap->va_rdev = doordev; /* device the file represents */ 141 vap->va_blksize = 0; /* fundamental block size */ 142 vap->va_nblocks = (fsblkcnt64_t)0; /* # of blocks allocated */ 143 vap->va_seq = 0; /* sequence number */ 144 145 return (0); 146 } 147 148 /* ARGSUSED */ 149 static void 150 door_inactive(struct vnode *vp, struct cred *cr) 151 { 152 door_node_t *dp = VTOD(vp); 153 154 mutex_enter(&vp->v_lock); 155 /* 156 * Once the door_node is unreferenced, it stays unreferenced, 157 * so we can simply return if there are active thread bindings; 158 * the final door_unbind_thread() will re-invoke us. 159 */ 160 ASSERT(vp->v_count == 1); 161 if (dp->door_bound_threads > 0) { 162 vp->v_count--; 163 mutex_exit(&vp->v_lock); 164 return; 165 } 166 mutex_exit(&vp->v_lock); 167 168 /* if not revoked, remove door from per-process list */ 169 if (dp->door_target) { 170 mutex_enter(&door_knob); 171 if (dp->door_target) /* recheck door_target under lock */ 172 door_list_delete(dp); 173 mutex_exit(&door_knob); 174 } 175 vn_invalid(vp); 176 vn_free(vp); 177 kmem_free(dp, sizeof (door_node_t)); 178 } 179 180 /* 181 * To avoid having bound threads interfere with unref processing, we 182 * don't use VN_HOLD/VN_RELE to track threads bound to our private 183 * pool. Instead, we keep a separate counter, also under v_lock. 184 */ 185 void 186 door_bind_thread(door_node_t *dp) 187 { 188 vnode_t *vp = DTOV(dp); 189 190 mutex_enter(&vp->v_lock); 191 dp->door_bound_threads++; 192 ASSERT(dp->door_bound_threads > 0 && vp->v_count > 0); 193 mutex_exit(&vp->v_lock); 194 } 195 196 void 197 door_unbind_thread(door_node_t *dp) 198 { 199 vnode_t *vp = DTOV(dp); 200 int do_inactive = 0; 201 202 mutex_enter(&vp->v_lock); 203 ASSERT(dp->door_bound_threads > 0); 204 if (--dp->door_bound_threads == 0 && vp->v_count == 0) { 205 /* set up for inactive handling */ 206 vp->v_count++; 207 do_inactive = 1; 208 } 209 mutex_exit(&vp->v_lock); 210 211 if (do_inactive) 212 door_inactive(vp, NULL); 213 } 214 215 /* ARGSUSED */ 216 static int 217 door_access(struct vnode *vp, int mode, int flags, struct cred *cr) 218 { 219 return (0); 220 } 221 222 /* ARGSUSED */ 223 static int 224 door_realvp(vnode_t *vp, vnode_t **vpp) 225 { 226 *vpp = vp; 227 return (0); 228 } 229