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 2008 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 /* 30 * This file containts all the functions required for interactions of 31 * event sources with the event port file system. 32 */ 33 34 #include <sys/types.h> 35 #include <sys/conf.h> 36 #include <sys/stat.h> 37 #include <sys/errno.h> 38 #include <sys/kmem.h> 39 #include <sys/debug.h> 40 #include <sys/file.h> 41 #include <sys/sysmacros.h> 42 #include <sys/systm.h> 43 #include <sys/bitmap.h> 44 #include <sys/rctl.h> 45 #include <sys/atomic.h> 46 #include <sys/poll_impl.h> 47 #include <sys/port_impl.h> 48 49 /* 50 * Maximum number of elements allowed to be passed in a single call of a 51 * port function (port_sendn(), port_getn(). We need to allocate kernel memory 52 * for all of them at once, so we can't let it scale without limit. 53 */ 54 uint_t port_max_list = PORT_MAX_LIST; 55 port_control_t port_control; /* Event port framework main structure */ 56 57 /* 58 * Block other threads from using a port. 59 * We enter holding portq->portq_mutex but 60 * we may drop and reacquire this lock. 61 * Callers must deal with this fact. 62 */ 63 void 64 port_block(port_queue_t *portq) 65 { 66 ASSERT(MUTEX_HELD(&portq->portq_mutex)); 67 68 while (portq->portq_flags & PORTQ_BLOCKED) 69 cv_wait(&portq->portq_block_cv, &portq->portq_mutex); 70 portq->portq_flags |= PORTQ_BLOCKED; 71 } 72 73 /* 74 * Undo port_block(portq). 75 */ 76 void 77 port_unblock(port_queue_t *portq) 78 { 79 ASSERT(MUTEX_HELD(&portq->portq_mutex)); 80 81 portq->portq_flags &= ~PORTQ_BLOCKED; 82 cv_signal(&portq->portq_block_cv); 83 } 84 85 /* 86 * Called from pollwakeup(PORT_SOURCE_FD source) to determine 87 * if the port's fd needs to be notified of poll events. If yes, 88 * we mark the port indicating that pollwakeup() is referring 89 * it so that the port_t does not disappear. pollwakeup() 90 * calls port_pollwkdone() after notifying. In port_pollwkdone(), 91 * we clear the hold on the port_t (clear PORTQ_POLLWK_PEND). 92 */ 93 int 94 port_pollwkup(port_t *pp) 95 { 96 int events = 0; 97 port_queue_t *portq; 98 portq = &pp->port_queue; 99 mutex_enter(&portq->portq_mutex); 100 101 /* 102 * Normally, we should not have a situation where PORTQ_POLLIN 103 * and PORTQ_POLLWK_PEND are set at the same time, but it is 104 * possible. So, in pollwakeup() we ensure that no new fd's get 105 * added to the pollhead between the time it notifies poll events 106 * and calls poll_wkupdone() where we clear the PORTQ_POLLWK_PEND flag. 107 */ 108 if (portq->portq_flags & PORTQ_POLLIN && 109 !(portq->portq_flags & PORTQ_POLLWK_PEND)) { 110 portq->portq_flags &= ~PORTQ_POLLIN; 111 portq->portq_flags |= PORTQ_POLLWK_PEND; 112 events = POLLIN; 113 } 114 mutex_exit(&portq->portq_mutex); 115 return (events); 116 } 117 118 void 119 port_pollwkdone(port_t *pp) 120 { 121 port_queue_t *portq; 122 portq = &pp->port_queue; 123 ASSERT(portq->portq_flags & PORTQ_POLLWK_PEND); 124 mutex_enter(&portq->portq_mutex); 125 portq->portq_flags &= ~PORTQ_POLLWK_PEND; 126 cv_signal(&pp->port_cv); 127 mutex_exit(&portq->portq_mutex); 128 } 129 130 131 /* 132 * The port_send_event() function is used by all event sources to submit 133 * trigerred events to a port. All the data required for the event management 134 * is already stored in the port_kevent_t structure. 135 * The event port internal data is stored in the port_kevent_t structure 136 * during the allocation time (see port_alloc_event()). The data related to 137 * the event itself and to the event source management is stored in the 138 * port_kevent_t structure between the allocation time and submit time 139 * (see port_init_event()). 140 * 141 * This function is often called from interrupt level. 142 */ 143 void 144 port_send_event(port_kevent_t *pkevp) 145 { 146 port_queue_t *portq; 147 148 portq = &pkevp->portkev_port->port_queue; 149 mutex_enter(&portq->portq_mutex); 150 151 if (pkevp->portkev_flags & PORT_KEV_DONEQ) { 152 /* Event already in the port queue */ 153 if (pkevp->portkev_source == PORT_SOURCE_FD) { 154 mutex_exit(&pkevp->portkev_lock); 155 } 156 mutex_exit(&portq->portq_mutex); 157 return; 158 } 159 160 /* put event in the port queue */ 161 list_insert_tail(&portq->portq_list, pkevp); 162 portq->portq_nent++; 163 164 /* 165 * Remove the PORTQ_WAIT_EVENTS flag to indicate 166 * that new events are available. 167 */ 168 portq->portq_flags &= ~PORTQ_WAIT_EVENTS; 169 pkevp->portkev_flags |= PORT_KEV_DONEQ; /* event enqueued */ 170 171 if (pkevp->portkev_source == PORT_SOURCE_FD) { 172 mutex_exit(&pkevp->portkev_lock); 173 } 174 175 /* Check if thread is in port_close() waiting for outstanding events */ 176 if (portq->portq_flags & PORTQ_CLOSE) { 177 /* Check if all outstanding events are already in port queue */ 178 if (pkevp->portkev_port->port_curr <= portq->portq_nent) 179 cv_signal(&portq->portq_closecv); 180 } 181 182 if (portq->portq_getn == 0) { 183 /* 184 * No thread retrieving events -> check if enough events are 185 * available to satify waiting threads. 186 */ 187 if (portq->portq_thread && 188 (portq->portq_nent >= portq->portq_nget)) 189 cv_signal(&portq->portq_thread->portget_cv); 190 } 191 192 /* 193 * If some thread is polling the port's fd, then notify it. 194 * For PORT_SOURCE_FD source, we don't need to call pollwakeup() 195 * here as it will result in a recursive call(PORT_SOURCE_FD source 196 * is pollwakeup()). Therefore pollwakeup() itself will notify the 197 * ports if being polled. 198 */ 199 if (pkevp->portkev_source != PORT_SOURCE_FD && 200 portq->portq_flags & PORTQ_POLLIN) { 201 port_t *pp; 202 203 portq->portq_flags &= ~PORTQ_POLLIN; 204 /* 205 * Need to save port_t for calling pollwakeup since port_getn() 206 * may end up freeing pkevp once portq_mutex is dropped. 207 */ 208 pp = pkevp->portkev_port; 209 mutex_exit(&portq->portq_mutex); 210 pollwakeup(&pp->port_pollhd, POLLIN); 211 } else { 212 mutex_exit(&portq->portq_mutex); 213 } 214 } 215 216 /* 217 * The port_alloc_event() function has to be used by all event sources 218 * to request an slot for event notification. 219 * The slot reservation could be denied because of lack of resources. 220 * For that reason the event source should allocate an event slot as early 221 * as possible and be prepared to get an error code instead of the 222 * port event pointer. 223 * Al current event sources allocate an event slot during a system call 224 * entry. They return an error code to the application if an event slot 225 * could not be reserved. 226 * It is also recommended to associate the event source with the port 227 * before some other port function is used. 228 * The port argument is a file descriptor obtained by the application as 229 * a return value of port_create(). 230 * Possible values of flags are: 231 * PORT_ALLOC_DEFAULT 232 * This is the standard type of port events. port_get(n) will free this 233 * type of event structures as soon as the events are delivered to the 234 * application. 235 * PORT_ALLOC_PRIVATE 236 * This type of event will be use for private use of the event source. 237 * The port_get(n) function will deliver events of such an structure to 238 * the application but it will not free the event structure itself. 239 * The event source must free this structure using port_free_event(). 240 * PORT_ALLOC_CACHED 241 * This type of events is used when the event source helds an own 242 * cache. 243 * The port_get(n) function will deliver events of such an structure to 244 * the application but it will not free the event structure itself. 245 * The event source must free this structure using port_free_event(). 246 */ 247 int 248 port_alloc_event(int port, int flags, int source, port_kevent_t **pkevpp) 249 { 250 port_t *pp; 251 file_t *fp; 252 port_kevent_t *pkevp; 253 254 if ((fp = getf(port)) == NULL) 255 return (EBADF); 256 257 if (fp->f_vnode->v_type != VPORT) { 258 releasef(port); 259 return (EBADFD); 260 } 261 262 pkevp = kmem_cache_alloc(port_control.pc_cache, KM_NOSLEEP); 263 if (pkevp == NULL) { 264 releasef(port); 265 return (ENOMEM); 266 } 267 268 /* 269 * port_max_events is controlled by the resource control 270 * process.port-max-events 271 */ 272 pp = VTOEP(fp->f_vnode); 273 mutex_enter(&pp->port_queue.portq_mutex); 274 if (pp->port_curr >= pp->port_max_events) { 275 mutex_exit(&pp->port_queue.portq_mutex); 276 kmem_cache_free(port_control.pc_cache, pkevp); 277 releasef(port); 278 return (EAGAIN); 279 } 280 pp->port_curr++; 281 mutex_exit(&pp->port_queue.portq_mutex); 282 283 bzero(pkevp, sizeof (port_kevent_t)); 284 mutex_init(&pkevp->portkev_lock, NULL, MUTEX_DEFAULT, NULL); 285 pkevp->portkev_source = source; 286 pkevp->portkev_flags = flags; 287 pkevp->portkev_pid = curproc->p_pid; 288 pkevp->portkev_port = pp; 289 *pkevpp = pkevp; 290 releasef(port); 291 return (0); 292 } 293 294 /* 295 * This function is faster than the standard port_alloc_event() and 296 * can be used when the event source already allocated an event from 297 * a port. 298 */ 299 int 300 port_dup_event(port_kevent_t *pkevp, port_kevent_t **pkevdupp, int flags) 301 { 302 int error; 303 304 error = port_alloc_event_local(pkevp->portkev_port, 305 pkevp->portkev_source, flags, pkevdupp); 306 if (error == 0) 307 (*pkevdupp)->portkev_pid = pkevp->portkev_pid; 308 return (error); 309 } 310 311 /* 312 * port_alloc_event_local() is reserved for internal use only. 313 * It is doing the same job as port_alloc_event() but with the event port 314 * pointer as the first argument. 315 * The check of the validity of the port file descriptor is skipped here. 316 */ 317 int 318 port_alloc_event_local(port_t *pp, int source, int flags, 319 port_kevent_t **pkevpp) 320 { 321 port_kevent_t *pkevp; 322 323 pkevp = kmem_cache_alloc(port_control.pc_cache, KM_NOSLEEP); 324 if (pkevp == NULL) 325 return (ENOMEM); 326 327 mutex_enter(&pp->port_queue.portq_mutex); 328 if (pp->port_curr >= pp->port_max_events) { 329 mutex_exit(&pp->port_queue.portq_mutex); 330 kmem_cache_free(port_control.pc_cache, pkevp); 331 return (EAGAIN); 332 } 333 pp->port_curr++; 334 mutex_exit(&pp->port_queue.portq_mutex); 335 336 bzero(pkevp, sizeof (port_kevent_t)); 337 mutex_init(&pkevp->portkev_lock, NULL, MUTEX_DEFAULT, NULL); 338 pkevp->portkev_flags = flags; 339 pkevp->portkev_port = pp; 340 pkevp->portkev_source = source; 341 pkevp->portkev_pid = curproc->p_pid; 342 *pkevpp = pkevp; 343 return (0); 344 } 345 346 /* 347 * port_alloc_event_block() has the same functionality of port_alloc_event() + 348 * - it blocks if not enough event slots are available and 349 * - it blocks if not enough memory is available. 350 * Currently port_dispatch() is using this function to increase the 351 * reliability of event delivery for library event sources. 352 */ 353 int 354 port_alloc_event_block(port_t *pp, int source, int flags, 355 port_kevent_t **pkevpp) 356 { 357 port_kevent_t *pkevp = 358 kmem_cache_alloc(port_control.pc_cache, KM_SLEEP); 359 360 mutex_enter(&pp->port_queue.portq_mutex); 361 while (pp->port_curr >= pp->port_max_events) { 362 if (!cv_wait_sig(&pp->port_cv, &pp->port_queue.portq_mutex)) { 363 /* signal detected */ 364 mutex_exit(&pp->port_queue.portq_mutex); 365 kmem_cache_free(port_control.pc_cache, pkevp); 366 return (EINTR); 367 } 368 } 369 pp->port_curr++; 370 mutex_exit(&pp->port_queue.portq_mutex); 371 372 bzero(pkevp, sizeof (port_kevent_t)); 373 mutex_init(&pkevp->portkev_lock, NULL, MUTEX_DEFAULT, NULL); 374 pkevp->portkev_flags = flags; 375 pkevp->portkev_port = pp; 376 pkevp->portkev_source = source; 377 pkevp->portkev_pid = curproc->p_pid; 378 *pkevpp = pkevp; 379 return (0); 380 } 381 382 /* 383 * Take an event out of the port queue 384 */ 385 static void 386 port_remove_event_doneq(port_kevent_t *pkevp, port_queue_t *portq) 387 { 388 ASSERT(MUTEX_HELD(&portq->portq_mutex)); 389 list_remove(&portq->portq_list, pkevp); 390 portq->portq_nent--; 391 pkevp->portkev_flags &= ~PORT_KEV_DONEQ; 392 } 393 394 /* 395 * The port_remove_done_event() function takes a fired event out of the 396 * port queue. 397 * Currently this function is required to cancel a fired event because 398 * the application is delivering new association data (see port_associate_fd()). 399 */ 400 int 401 port_remove_done_event(port_kevent_t *pkevp) 402 { 403 port_queue_t *portq; 404 int removed = 0; 405 406 portq = &pkevp->portkev_port->port_queue; 407 mutex_enter(&portq->portq_mutex); 408 /* wait for port_get() or port_getn() */ 409 port_block(portq); 410 if (pkevp->portkev_flags & PORT_KEV_DONEQ) { 411 /* event still in port queue */ 412 if (portq->portq_getn) { 413 /* 414 * There could be still fired events in the temp queue; 415 * push those events back to the port queue and 416 * remove requested event afterwards. 417 */ 418 port_push_eventq(portq); 419 } 420 /* now remove event from the port queue */ 421 port_remove_event_doneq(pkevp, portq); 422 removed = 1; 423 } 424 port_unblock(portq); 425 mutex_exit(&portq->portq_mutex); 426 return (removed); 427 } 428 429 /* 430 * Return port event back to the kmem_cache. 431 * If the event is currently in the port queue the event itself will only 432 * be set as invalid. The port_get(n) function will not deliver such events 433 * to the application and it will return them back to the kmem_cache. 434 */ 435 void 436 port_free_event(port_kevent_t *pkevp) 437 { 438 port_queue_t *portq; 439 port_t *pp; 440 441 pp = pkevp->portkev_port; 442 if (pp == NULL) 443 return; 444 if (pkevp->portkev_flags & PORT_ALLOC_PRIVATE) { 445 port_free_event_local(pkevp, 0); 446 return; 447 } 448 449 portq = &pp->port_queue; 450 mutex_enter(&portq->portq_mutex); 451 port_block(portq); 452 if (pkevp->portkev_flags & PORT_KEV_DONEQ) { 453 pkevp->portkev_flags |= PORT_KEV_FREE; 454 pkevp->portkev_callback = NULL; 455 port_unblock(portq); 456 mutex_exit(&portq->portq_mutex); 457 return; 458 } 459 port_unblock(portq); 460 461 if (pkevp->portkev_flags & PORT_KEV_CACHED) { 462 mutex_exit(&portq->portq_mutex); 463 return; 464 } 465 466 if (--pp->port_curr < pp->port_max_events) 467 cv_signal(&pp->port_cv); 468 if (portq->portq_flags & PORTQ_CLOSE) { 469 /* 470 * Another thread is closing the event port. 471 * That thread will sleep until all allocated event 472 * structures returned to the event port framework. 473 * The portq_mutex is used to synchronize the status 474 * of the allocated event structures (port_curr). 475 */ 476 if (pp->port_curr <= portq->portq_nent) 477 cv_signal(&portq->portq_closecv); 478 } 479 mutex_exit(&portq->portq_mutex); 480 port_free_event_local(pkevp, 1); 481 } 482 483 /* 484 * This event port internal function is used by port_free_event() and 485 * other port internal functions to return event structures back to the 486 * kmem_cache. 487 */ 488 void 489 port_free_event_local(port_kevent_t *pkevp, int counter) 490 { 491 port_t *pp = pkevp->portkev_port; 492 port_queue_t *portq = &pp->port_queue; 493 int wakeup; 494 495 pkevp->portkev_callback = NULL; 496 pkevp->portkev_flags = 0; 497 pkevp->portkev_port = NULL; 498 mutex_destroy(&pkevp->portkev_lock); 499 kmem_cache_free(port_control.pc_cache, pkevp); 500 501 mutex_enter(&portq->portq_mutex); 502 if (counter == 0) { 503 if (--pp->port_curr < pp->port_max_events) 504 cv_signal(&pp->port_cv); 505 } 506 wakeup = (portq->portq_flags & PORTQ_POLLOUT); 507 portq->portq_flags &= ~PORTQ_POLLOUT; 508 mutex_exit(&portq->portq_mutex); 509 510 /* Submit a POLLOUT event if requested */ 511 if (wakeup) 512 pollwakeup(&pp->port_pollhd, POLLOUT); 513 } 514 515 /* 516 * port_init_event(port_event_t *pev, uintptr_t object, void *user, 517 * int (*port_callback)(void *, int *, pid_t, int, void *), void *sysarg); 518 * This function initializes most of the "wired" elements of the port 519 * event structure. This is normally being used just after the allocation 520 * of the port event structure. 521 * pkevp : pointer to the port event structure 522 * object : object associated with this event structure 523 * user : user defined pointer delivered with the association function 524 * port_callback: 525 * Address of the callback function which will be called 526 * - just before the event is delivered to the application. 527 * The callback function is called in user context and can be 528 * used for copyouts, e.g. 529 * - on close() or dissociation of the event. The sub-system 530 * must remove immediately every existing association of 531 * some object with this event. 532 * sysarg : event source propietary data 533 */ 534 void 535 port_init_event(port_kevent_t *pkevp, uintptr_t object, void *user, 536 int (*port_callback)(void *, int *, pid_t, int, void *), 537 void *sysarg) 538 { 539 pkevp->portkev_object = object; 540 pkevp->portkev_user = user; 541 pkevp->portkev_callback = port_callback; 542 pkevp->portkev_arg = sysarg; 543 } 544 545 /* 546 * This routine removes a portfd_t from the fd cache's hash table. 547 */ 548 void 549 port_pcache_remove_fd(port_fdcache_t *pcp, portfd_t *pfd) 550 { 551 polldat_t *lpdp; 552 polldat_t *cpdp; 553 portfd_t **bucket; 554 polldat_t *pdp = PFTOD(pfd); 555 556 ASSERT(MUTEX_HELD(&pcp->pc_lock)); 557 bucket = PORT_FD_BUCKET(pcp, pdp->pd_fd); 558 cpdp = PFTOD(*bucket); 559 if (pdp == cpdp) { 560 *bucket = PDTOF(pdp->pd_hashnext); 561 if (--pcp->pc_fdcount == 0) { 562 /* 563 * signal the thread which may have blocked in 564 * port_close_sourcefd() on lastclose waiting 565 * for pc_fdcount to drop to 0. 566 */ 567 cv_signal(&pcp->pc_lclosecv); 568 } 569 kmem_free(pfd, sizeof (portfd_t)); 570 return; 571 } 572 573 while (cpdp != NULL) { 574 lpdp = cpdp; 575 cpdp = cpdp->pd_hashnext; 576 if (cpdp == pdp) { 577 /* polldat struct found */ 578 lpdp->pd_hashnext = pdp->pd_hashnext; 579 if (--pcp->pc_fdcount == 0) { 580 /* 581 * signal the thread which may have blocked in 582 * port_close_sourcefd() on lastclose waiting 583 * for pc_fdcount to drop to 0. 584 */ 585 cv_signal(&pcp->pc_lclosecv); 586 } 587 break; 588 } 589 } 590 ASSERT(cpdp != NULL); 591 kmem_free(pfd, sizeof (portfd_t)); 592 } 593 594 /* 595 * The port_push_eventq() function is used to move all remaining events 596 * from the temporary queue used in port_get(n)() to the standard port 597 * queue. 598 */ 599 void 600 port_push_eventq(port_queue_t *portq) 601 { 602 /* 603 * Append temporary portq_get_list to the port queue. On return 604 * the temporary portq_get_list is empty. 605 */ 606 list_move_tail(&portq->portq_list, &portq->portq_get_list); 607 portq->portq_nent += portq->portq_tnent; 608 portq->portq_tnent = 0; 609 } 610 611 /* 612 * The port_remove_fd_object() function frees all resources associated with 613 * delivered portfd_t structure. Returns 1 if the port_kevent was found 614 * and removed from the port queue. 615 */ 616 int 617 port_remove_fd_object(portfd_t *pfd, port_t *pp, port_fdcache_t *pcp) 618 { 619 port_queue_t *portq; 620 polldat_t *pdp = PFTOD(pfd); 621 port_kevent_t *pkevp; 622 int error; 623 int removed = 0; 624 625 ASSERT(MUTEX_HELD(&pcp->pc_lock)); 626 if (pdp->pd_php != NULL) { 627 pollhead_delete(pdp->pd_php, pdp); 628 pdp->pd_php = NULL; 629 } 630 pkevp = pdp->pd_portev; 631 portq = &pp->port_queue; 632 mutex_enter(&portq->portq_mutex); 633 port_block(portq); 634 if (pkevp->portkev_flags & PORT_KEV_DONEQ) { 635 if (portq->portq_getn && portq->portq_tnent) { 636 /* 637 * move events from the temporary "get" queue 638 * back to the port queue 639 */ 640 port_push_eventq(portq); 641 } 642 /* cleanup merged port queue */ 643 port_remove_event_doneq(pkevp, portq); 644 removed = 1; 645 } 646 port_unblock(portq); 647 mutex_exit(&portq->portq_mutex); 648 if (pkevp->portkev_callback) { 649 (void) (*pkevp->portkev_callback)(pkevp->portkev_arg, 650 &error, pkevp->portkev_pid, PORT_CALLBACK_DISSOCIATE, 651 pkevp); 652 } 653 port_free_event_local(pkevp, 0); 654 655 /* remove polldat struct */ 656 port_pcache_remove_fd(pcp, pfd); 657 return (removed); 658 } 659 660 /* 661 * The port_close_fd() function dissociates a file descriptor from a port 662 * and removes all allocated resources. 663 * close(2) detects in the uf_entry_t structure that the fd is associated 664 * with a port (at least one port). 665 * The fd can be associated with several ports. 666 */ 667 void 668 port_close_pfd(portfd_t *pfd) 669 { 670 port_t *pp; 671 port_fdcache_t *pcp; 672 673 /* 674 * the portfd_t passed in should be for this proc. 675 */ 676 ASSERT(curproc->p_pid == PFTOD(pfd)->pd_portev->portkev_pid); 677 pp = PFTOD(pfd)->pd_portev->portkev_port; 678 pcp = pp->port_queue.portq_pcp; 679 mutex_enter(&pcp->pc_lock); 680 (void) port_remove_fd_object(pfd, pp, pcp); 681 mutex_exit(&pcp->pc_lock); 682 } 683 684 /* 685 * The port_associate_ksource() function associates an event source with a port. 686 * On port_close() all associated sources are requested to free all local 687 * resources associated with the event port. 688 * The association of a source with a port can only be done one time. Further 689 * calls of this function will only increment the reference counter. 690 * The allocated port_source_t structure is removed from the port as soon as 691 * the reference counter becomes 0. 692 */ 693 /* ARGSUSED */ 694 int 695 port_associate_ksource(int port, int source, port_source_t **portsrc, 696 void (*port_src_close)(void *, int, pid_t, int), void *arg, 697 int (*port_src_associate)(port_kevent_t *, int, int, uintptr_t, void *)) 698 { 699 port_t *pp; 700 file_t *fp; 701 port_source_t **ps; 702 port_source_t *pse; 703 704 if ((fp = getf(port)) == NULL) 705 return (EBADF); 706 707 if (fp->f_vnode->v_type != VPORT) { 708 releasef(port); 709 return (EBADFD); 710 } 711 pp = VTOEP(fp->f_vnode); 712 713 mutex_enter(&pp->port_queue.portq_source_mutex); 714 ps = &pp->port_queue.portq_scache[PORT_SHASH(source)]; 715 for (pse = *ps; pse != NULL; pse = pse->portsrc_next) { 716 if (pse->portsrc_source == source) 717 break; 718 } 719 720 if (pse == NULL) { 721 /* Create association of the event source with the port */ 722 pse = kmem_zalloc(sizeof (port_source_t), KM_NOSLEEP); 723 if (pse == NULL) { 724 mutex_exit(&pp->port_queue.portq_source_mutex); 725 releasef(port); 726 return (ENOMEM); 727 } 728 pse->portsrc_source = source; 729 pse->portsrc_close = port_src_close; 730 pse->portsrc_closearg = arg; 731 pse->portsrc_cnt = 1; 732 if (*ps) 733 pse->portsrc_next = (*ps)->portsrc_next; 734 *ps = pse; 735 } else { 736 /* entry already available, source is only requesting count */ 737 pse->portsrc_cnt++; 738 } 739 mutex_exit(&pp->port_queue.portq_source_mutex); 740 releasef(port); 741 if (portsrc) 742 *portsrc = pse; 743 return (0); 744 } 745 746 /* 747 * The port_dissociate_ksource() function dissociates an event source from 748 * a port. 749 */ 750 int 751 port_dissociate_ksource(int port, int source, port_source_t *ps) 752 { 753 port_t *pp; 754 file_t *fp; 755 port_source_t **psh; 756 757 if (ps == NULL) 758 return (EINVAL); 759 760 if ((fp = getf(port)) == NULL) 761 return (EBADF); 762 763 if (fp->f_vnode->v_type != VPORT) { 764 releasef(port); 765 return (EBADFD); 766 } 767 pp = VTOEP(fp->f_vnode); 768 769 mutex_enter(&pp->port_queue.portq_source_mutex); 770 if (--ps->portsrc_cnt == 0) { 771 /* last association removed -> free source structure */ 772 if (ps->portsrc_prev == NULL) { 773 /* first entry */ 774 psh = &pp->port_queue.portq_scache[PORT_SHASH(source)]; 775 *psh = ps->portsrc_next; 776 if (ps->portsrc_next) 777 ps->portsrc_next->portsrc_prev = NULL; 778 } else { 779 ps->portsrc_prev->portsrc_next = ps->portsrc_next; 780 if (ps->portsrc_next) 781 ps->portsrc_next->portsrc_prev = 782 ps->portsrc_prev; 783 } 784 kmem_free(ps, sizeof (port_source_t)); 785 } 786 mutex_exit(&pp->port_queue.portq_source_mutex); 787 releasef(port); 788 return (0); 789 } 790 791 void 792 free_fopdata(vnode_t *vp) 793 { 794 portfop_vp_t *pvp; 795 pvp = vp->v_fopdata; 796 ASSERT(pvp->pvp_femp == NULL); 797 mutex_destroy(&pvp->pvp_mutex); 798 list_destroy(&pvp->pvp_pfoplist); 799 kmem_free(pvp, sizeof (*pvp)); 800 vp->v_fopdata = NULL; 801 } 802