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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 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/vfs_opreg.h> 32 #include <sys/kmem.h> 33 #include <fs/fs_subr.h> 34 #include <sys/proc.h> 35 #include <sys/kstat.h> 36 #include <sys/port_impl.h> 37 38 /* local functions */ 39 static int port_open(struct vnode **, int, cred_t *); 40 static int port_close(struct vnode *, int, int, offset_t, cred_t *); 41 static int port_getattr(struct vnode *, struct vattr *, int, cred_t *); 42 static int port_access(struct vnode *, int, int, cred_t *); 43 static int port_realvp(vnode_t *, vnode_t **); 44 static int port_poll(vnode_t *, short, int, short *, struct pollhead **); 45 static void port_inactive(struct vnode *, cred_t *); 46 47 const fs_operation_def_t port_vnodeops_template[] = { 48 VOPNAME_OPEN, { .vop_open = port_open }, 49 VOPNAME_CLOSE, { .vop_close = port_close }, 50 VOPNAME_GETATTR, { .vop_getattr = port_getattr }, 51 VOPNAME_ACCESS, { .vop_access = port_access }, 52 VOPNAME_INACTIVE, { .vop_inactive = port_inactive }, 53 VOPNAME_FRLOCK, { .error = fs_error }, 54 VOPNAME_REALVP, { .vop_realvp = port_realvp }, 55 VOPNAME_POLL, { .vop_poll = port_poll }, 56 VOPNAME_PATHCONF, { .error = fs_error }, 57 VOPNAME_DISPOSE, { .error = fs_error }, 58 VOPNAME_GETSECATTR, { .error = fs_error }, 59 VOPNAME_SHRLOCK, { .error = fs_error }, 60 NULL, NULL 61 }; 62 63 /* ARGSUSED */ 64 static int 65 port_open(struct vnode **vpp, int flag, cred_t *cr) 66 { 67 return (0); 68 } 69 70 /* 71 * port_discard_events() scans the port event queue for events owned 72 * by current proc. Non-shareable events will be discarded, all other 73 * events remain in the event queue. 74 */ 75 void 76 port_discard_events(port_queue_t *portq) 77 { 78 port_kevent_t *kevp; 79 pid_t pid = curproc->p_pid; 80 81 /* 82 * The call to port_block() is required to avoid interaction 83 * with other threads in port_get(n). 84 */ 85 mutex_enter(&portq->portq_mutex); 86 port_block(portq); 87 port_push_eventq(portq); /* empty temporary queue */ 88 kevp = list_head(&portq->portq_list); 89 while (kevp) { 90 if (kevp->portkev_pid == pid) { 91 /* own event, check if it is shareable */ 92 if (kevp->portkev_flags & PORT_KEV_NOSHARE) 93 kevp->portkev_flags |= PORT_KEV_FREE; 94 } 95 kevp = list_next(&portq->portq_list, kevp); 96 } 97 port_unblock(portq); 98 mutex_exit(&portq->portq_mutex); 99 } 100 101 /* 102 * Called from port_close(). 103 * Free all kernel events structures which are still in the event queue. 104 */ 105 static void 106 port_close_events(port_queue_t *portq) 107 { 108 port_kevent_t *pkevp; 109 int events; /* ignore events */ 110 111 mutex_enter(&portq->portq_mutex); 112 while (pkevp = list_head(&portq->portq_list)) { 113 portq->portq_nent--; 114 list_remove(&portq->portq_list, pkevp); 115 if (pkevp->portkev_callback) { 116 (void) (*pkevp->portkev_callback)(pkevp->portkev_arg, 117 &events, pkevp->portkev_pid, PORT_CALLBACK_CLOSE, 118 pkevp); 119 } 120 mutex_exit(&portq->portq_mutex); 121 port_free_event_local(pkevp, 0); 122 mutex_enter(&portq->portq_mutex); 123 } 124 125 /* 126 * Wait for any thread in pollwakeup(), accessing this port to 127 * finish. 128 */ 129 while (portq->portq_flags & PORTQ_POLLWK_PEND) { 130 cv_wait(&portq->portq_closecv, &portq->portq_mutex); 131 } 132 mutex_exit(&portq->portq_mutex); 133 } 134 135 /* 136 * The port_close() function is called from standard close(2) when 137 * the file descriptor is of type S_IFPORT/VPORT. 138 * Port file descriptors behave like standard file descriptors. It means, 139 * the port file/vnode is only destroyed on last close. 140 * If the reference counter is > 1 then 141 * - sources associated with the port will be notified about the close, 142 * - objects associated with the port will be dissociated, 143 * - pending and delivered events will be discarded. 144 * On last close all references and caches will be removed. The vnode itself 145 * will be destroyed with VOP_RELE(). 146 */ 147 /* ARGSUSED */ 148 static int 149 port_close(struct vnode *vp, int flag, int count, offset_t offset, cred_t *cr) 150 { 151 port_t *pp; 152 port_queue_t *portq; 153 port_source_t *ps; 154 port_source_t *ps_next; 155 int source; 156 157 pp = VTOEP(vp); 158 mutex_enter(&pp->port_mutex); 159 if (pp->port_flags & PORT_CLOSED) { 160 mutex_exit(&pp->port_mutex); 161 return (0); 162 } 163 mutex_exit(&pp->port_mutex); 164 165 portq = &pp->port_queue; 166 if (count > 1) { 167 /* 168 * It is not the last close. 169 * Remove/free all event resources owned by the current proc 170 * First notify all with the port associated sources about the 171 * close(2). The last argument of the close callback function 172 * advises the source about the type of of the close. 173 * If the port was set in alert mode by the curren process then 174 * remove the alert mode. 175 */ 176 177 /* check alert mode of the port */ 178 mutex_enter(&portq->portq_mutex); 179 if ((portq->portq_flags & PORTQ_ALERT) && 180 (portq->portq_alert.portal_pid == curproc->p_pid)) 181 portq->portq_flags &= ~PORTQ_ALERT; 182 mutex_exit(&portq->portq_mutex); 183 184 /* notify all event sources about port_close() */ 185 mutex_enter(&portq->portq_source_mutex); 186 for (source = 0; source < PORT_SCACHE_SIZE; source++) { 187 ps = portq->portq_scache[PORT_SHASH(source)]; 188 for (; ps != NULL; ps = ps->portsrc_next) { 189 if (ps->portsrc_close != NULL) 190 (*ps->portsrc_close) 191 (ps->portsrc_closearg, pp->port_fd, 192 curproc->p_pid, 0); 193 } 194 } 195 mutex_exit(&portq->portq_source_mutex); 196 port_discard_events(&pp->port_queue); 197 return (0); 198 } 199 200 /* 201 * We are executing the last close of the port -> discard everything 202 * Make sure that all threads/processes accessing this port leave 203 * the kernel immediately. 204 */ 205 206 mutex_enter(&portq->portq_mutex); 207 portq->portq_flags |= PORTQ_CLOSE; 208 while (portq->portq_thrcnt > 0) { 209 if (portq->portq_thread != NULL) 210 cv_signal(&portq->portq_thread->portget_cv); 211 cv_wait(&portq->portq_closecv, &portq->portq_mutex); 212 } 213 mutex_exit(&portq->portq_mutex); 214 215 /* 216 * Send "last close" message to associated sources. 217 * - new event allocation requests are being denied since uf_file entry 218 * was set to NULL in closeandsetf(). 219 * - all still allocated event structures must be returned to the 220 * port immediately: 221 * - call port_free_event(*event) or 222 * - call port_send_event(*event) to complete event operations 223 * which need activities in a dedicated process environment. 224 * The port_close() function waits until all allocated event structures 225 * are delivered back to the port. 226 */ 227 228 mutex_enter(&portq->portq_source_mutex); 229 for (source = 0; source < PORT_SCACHE_SIZE; source++) { 230 ps = portq->portq_scache[PORT_SHASH(source)]; 231 for (; ps != NULL; ps = ps_next) { 232 ps_next = ps->portsrc_next; 233 if (ps->portsrc_close != NULL) 234 (*ps->portsrc_close)(ps->portsrc_closearg, 235 pp->port_fd, curproc->p_pid, 1); 236 kmem_free(ps, sizeof (port_source_t)); 237 } 238 } 239 kmem_free(portq->portq_scache, 240 PORT_SCACHE_SIZE * sizeof (port_source_t *)); 241 portq->portq_scache = NULL; 242 mutex_exit(&portq->portq_source_mutex); 243 244 mutex_enter(&portq->portq_mutex); 245 /* Wait for outstanding events */ 246 while (pp->port_curr > portq->portq_nent) 247 cv_wait(&portq->portq_closecv, &portq->portq_mutex); 248 mutex_exit(&portq->portq_mutex); 249 250 /* 251 * If PORT_SOURCE_FD objects were not associated with the port then 252 * it is necessary to free the port_fdcache structure here. 253 */ 254 255 if (portq->portq_pcp != NULL) { 256 mutex_destroy(&portq->portq_pcp->pc_lock); 257 kmem_free(portq->portq_pcp, sizeof (port_fdcache_t)); 258 portq->portq_pcp = NULL; 259 } 260 261 /* 262 * Now all events are passed back to the port, 263 * discard remaining events in the port queue 264 */ 265 266 port_close_events(portq); 267 return (0); 268 } 269 270 /* 271 * The port_poll() function is the VOP_POLL() entry of event ports. 272 * Event ports return: 273 * POLLIN : events are available in the event queue 274 * POLLOUT : event queue can still accept events 275 */ 276 /*ARGSUSED*/ 277 static int 278 port_poll(vnode_t *vp, short events, int anyyet, short *reventsp, 279 struct pollhead **phpp) 280 { 281 port_t *pp; 282 port_queue_t *portq; 283 short levents; 284 285 pp = VTOEP(vp); 286 portq = &pp->port_queue; 287 levents = 0; 288 mutex_enter(&portq->portq_mutex); 289 if (portq->portq_nent) 290 levents = POLLIN; 291 if (pp->port_curr < pp->port_max_events) 292 levents |= POLLOUT; 293 levents &= events; 294 *reventsp = levents; 295 if (levents == 0) { 296 if (!anyyet) { 297 *phpp = &pp->port_pollhd; 298 portq->portq_flags |= 299 events & POLLIN ? PORTQ_POLLIN : 0; 300 portq->portq_flags |= 301 events & POLLOUT ? PORTQ_POLLOUT : 0; 302 } 303 } 304 mutex_exit(&portq->portq_mutex); 305 return (0); 306 } 307 308 309 /* ARGSUSED */ 310 static int 311 port_getattr(struct vnode *vp, struct vattr *vap, int flags, cred_t *cr) 312 { 313 port_t *pp; 314 extern dev_t portdev; 315 316 pp = VTOEP(vp); 317 318 vap->va_mask = 0; /* bit-mask of attributes */ 319 vap->va_type = vp->v_type; /* vnode type (for create) */ 320 vap->va_mode = 0; /* file access mode */ 321 vap->va_uid = pp->port_uid; /* owner user id */ 322 vap->va_gid = pp->port_gid; /* owner group id */ 323 vap->va_fsid = portdev; /* file system id */ 324 vap->va_nodeid = (ino64_t)0; /* node id */ 325 vap->va_nlink = vp->v_count; /* number of references to file */ 326 vap->va_size = (u_offset_t)pp->port_queue.portq_nent; /* file size */ 327 vap->va_atime = pp->port_ctime; /* time of last access */ 328 vap->va_mtime = pp->port_ctime; /* time of last modification */ 329 vap->va_ctime = pp->port_ctime; /* time file ``created'' */ 330 vap->va_rdev = portdev; /* device the file represents */ 331 vap->va_blksize = 0; /* fundamental block size */ 332 vap->va_nblocks = (fsblkcnt64_t)0; /* # of blocks allocated */ 333 vap->va_seq = 0; /* sequence number */ 334 335 return (0); 336 } 337 338 /* 339 * Destroy the port. 340 */ 341 /* ARGSUSED */ 342 static void 343 port_inactive(struct vnode *vp, cred_t *cr) 344 { 345 port_t *pp = VTOEP(vp); 346 extern port_kstat_t port_kstat; 347 348 mutex_enter(&port_control.pc_mutex); 349 port_control.pc_nents--; 350 curproc->p_portcnt--; 351 port_kstat.pks_ports.value.ui32--; 352 mutex_exit(&port_control.pc_mutex); 353 vn_free(vp); 354 mutex_destroy(&pp->port_mutex); 355 mutex_destroy(&pp->port_queue.portq_mutex); 356 mutex_destroy(&pp->port_queue.portq_source_mutex); 357 kmem_free(pp, sizeof (port_t)); 358 } 359 360 /* ARGSUSED */ 361 static int 362 port_access(struct vnode *vp, int mode, int flags, cred_t *cr) 363 { 364 return (0); 365 } 366 367 /* ARGSUSED */ 368 static int 369 port_realvp(vnode_t *vp, vnode_t **vpp) 370 { 371 *vpp = vp; 372 return (0); 373 } 374