1 /* $NetBSD: fifo_vnops.c,v 1.66 2008/04/28 20:24:08 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Copyright (c) 1990, 1993, 1995 31 * The Regents of the University of California. All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 3. Neither the name of the University nor the names of its contributors 42 * may be used to endorse or promote products derived from this software 43 * without specific prior written permission. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 * 57 * @(#)fifo_vnops.c 8.10 (Berkeley) 5/27/95 58 */ 59 60 #include <sys/cdefs.h> 61 __KERNEL_RCSID(0, "$NetBSD: fifo_vnops.c,v 1.66 2008/04/28 20:24:08 martin Exp $"); 62 63 #include <sys/param.h> 64 #include <sys/systm.h> 65 #include <sys/proc.h> 66 #include <sys/time.h> 67 #include <sys/namei.h> 68 #include <sys/vnode.h> 69 #include <sys/socket.h> 70 #include <sys/protosw.h> 71 #include <sys/socketvar.h> 72 #include <sys/stat.h> 73 #include <sys/ioctl.h> 74 #include <sys/file.h> 75 #include <sys/errno.h> 76 #include <sys/kmem.h> 77 #include <sys/un.h> 78 #include <sys/poll.h> 79 #include <sys/event.h> 80 #include <sys/condvar.h> 81 82 #include <miscfs/fifofs/fifo.h> 83 #include <miscfs/genfs/genfs.h> 84 85 /* 86 * This structure is associated with the FIFO vnode and stores 87 * the state associated with the FIFO. 88 */ 89 struct fifoinfo { 90 struct socket *fi_readsock; 91 struct socket *fi_writesock; 92 kcondvar_t fi_rcv; 93 int fi_readers; 94 kcondvar_t fi_wcv; 95 int fi_writers; 96 }; 97 98 int (**fifo_vnodeop_p)(void *); 99 const struct vnodeopv_entry_desc fifo_vnodeop_entries[] = { 100 { &vop_default_desc, vn_default_error }, 101 { &vop_lookup_desc, fifo_lookup }, /* lookup */ 102 { &vop_create_desc, fifo_create }, /* create */ 103 { &vop_mknod_desc, fifo_mknod }, /* mknod */ 104 { &vop_open_desc, fifo_open }, /* open */ 105 { &vop_close_desc, fifo_close }, /* close */ 106 { &vop_access_desc, fifo_access }, /* access */ 107 { &vop_getattr_desc, fifo_getattr }, /* getattr */ 108 { &vop_setattr_desc, fifo_setattr }, /* setattr */ 109 { &vop_read_desc, fifo_read }, /* read */ 110 { &vop_write_desc, fifo_write }, /* write */ 111 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 112 { &vop_poll_desc, fifo_poll }, /* poll */ 113 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */ 114 { &vop_revoke_desc, fifo_revoke }, /* revoke */ 115 { &vop_mmap_desc, fifo_mmap }, /* mmap */ 116 { &vop_fsync_desc, fifo_fsync }, /* fsync */ 117 { &vop_seek_desc, fifo_seek }, /* seek */ 118 { &vop_remove_desc, fifo_remove }, /* remove */ 119 { &vop_link_desc, fifo_link }, /* link */ 120 { &vop_rename_desc, fifo_rename }, /* rename */ 121 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 122 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 123 { &vop_symlink_desc, fifo_symlink }, /* symlink */ 124 { &vop_readdir_desc, fifo_readdir }, /* readdir */ 125 { &vop_readlink_desc, fifo_readlink }, /* readlink */ 126 { &vop_abortop_desc, fifo_abortop }, /* abortop */ 127 { &vop_inactive_desc, fifo_inactive }, /* inactive */ 128 { &vop_reclaim_desc, fifo_reclaim }, /* reclaim */ 129 { &vop_lock_desc, fifo_lock }, /* lock */ 130 { &vop_unlock_desc, fifo_unlock }, /* unlock */ 131 { &vop_bmap_desc, fifo_bmap }, /* bmap */ 132 { &vop_strategy_desc, fifo_strategy }, /* strategy */ 133 { &vop_print_desc, fifo_print }, /* print */ 134 { &vop_islocked_desc, fifo_islocked }, /* islocked */ 135 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 136 { &vop_advlock_desc, fifo_advlock }, /* advlock */ 137 { &vop_bwrite_desc, fifo_bwrite }, /* bwrite */ 138 { &vop_putpages_desc, fifo_putpages }, /* putpages */ 139 { (struct vnodeop_desc*)NULL, (int(*)(void *))NULL } 140 }; 141 const struct vnodeopv_desc fifo_vnodeop_opv_desc = 142 { &fifo_vnodeop_p, fifo_vnodeop_entries }; 143 144 /* 145 * Trivial lookup routine that always fails. 146 */ 147 /* ARGSUSED */ 148 int 149 fifo_lookup(void *v) 150 { 151 struct vop_lookup_args /* { 152 struct vnode *a_dvp; 153 struct vnode **a_vpp; 154 struct componentname *a_cnp; 155 } */ *ap = v; 156 157 *ap->a_vpp = NULL; 158 return (ENOTDIR); 159 } 160 161 /* 162 * Open called to set up a new instance of a fifo or 163 * to find an active instance of a fifo. 164 */ 165 /* ARGSUSED */ 166 int 167 fifo_open(void *v) 168 { 169 struct vop_open_args /* { 170 struct vnode *a_vp; 171 int a_mode; 172 kauth_cred_t a_cred; 173 } */ *ap = v; 174 struct lwp *l = curlwp; 175 struct vnode *vp; 176 struct fifoinfo *fip; 177 struct proc *p; 178 struct socket *rso, *wso; 179 int error; 180 181 vp = ap->a_vp; 182 p = l->l_proc; 183 184 if ((fip = vp->v_fifoinfo) == NULL) { 185 fip = kmem_alloc(sizeof(*fip), KM_SLEEP); 186 vp->v_fifoinfo = fip; 187 error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0, l, NULL); 188 if (error != 0) { 189 kmem_free(fip, sizeof(*fip)); 190 vp->v_fifoinfo = NULL; 191 return (error); 192 } 193 fip->fi_readsock = rso; 194 error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0, l, rso); 195 if (error != 0) { 196 (void)soclose(rso); 197 kmem_free(fip, sizeof(*fip)); 198 vp->v_fifoinfo = NULL; 199 return (error); 200 } 201 fip->fi_writesock = wso; 202 solock(wso); 203 if ((error = unp_connect2(wso, rso, PRU_CONNECT2)) != 0) { 204 sounlock(wso); 205 (void)soclose(wso); 206 (void)soclose(rso); 207 kmem_free(fip, sizeof(*fip)); 208 vp->v_fifoinfo = NULL; 209 return (error); 210 } 211 fip->fi_readers = 0; 212 fip->fi_writers = 0; 213 wso->so_state |= SS_CANTRCVMORE; 214 rso->so_state |= SS_CANTSENDMORE; 215 cv_init(&fip->fi_rcv, "fiford"); 216 cv_init(&fip->fi_wcv, "fifowr"); 217 } else { 218 wso = fip->fi_writesock; 219 rso = fip->fi_readsock; 220 solock(wso); 221 } 222 223 if (ap->a_mode & FREAD) { 224 if (fip->fi_readers++ == 0) { 225 wso->so_state &= ~SS_CANTSENDMORE; 226 cv_broadcast(&fip->fi_wcv); 227 } 228 } 229 if (ap->a_mode & FWRITE) { 230 if (fip->fi_writers++ == 0) { 231 rso->so_state &= ~SS_CANTRCVMORE; 232 cv_broadcast(&fip->fi_rcv); 233 } 234 } 235 if (ap->a_mode & FREAD) { 236 if (ap->a_mode & O_NONBLOCK) { 237 } else { 238 while (!soreadable(rso) && fip->fi_writers == 0) { 239 VOP_UNLOCK(vp, 0); 240 error = cv_wait_sig(&fip->fi_rcv, 241 wso->so_lock); 242 sounlock(wso); 243 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 244 if (error) 245 goto bad; 246 solock(wso); 247 } 248 } 249 } 250 if (ap->a_mode & FWRITE) { 251 if (ap->a_mode & O_NONBLOCK) { 252 if (fip->fi_readers == 0) { 253 error = ENXIO; 254 sounlock(wso); 255 goto bad; 256 } 257 } else { 258 while (fip->fi_readers == 0) { 259 VOP_UNLOCK(vp, 0); 260 error = cv_wait_sig(&fip->fi_wcv, 261 wso->so_lock); 262 sounlock(wso); 263 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 264 if (error) 265 goto bad; 266 solock(wso); 267 } 268 } 269 } 270 sounlock(wso); 271 return (0); 272 bad: 273 VOP_CLOSE(vp, ap->a_mode, ap->a_cred); 274 return (error); 275 } 276 277 /* 278 * Vnode op for read 279 */ 280 /* ARGSUSED */ 281 int 282 fifo_read(void *v) 283 { 284 struct vop_read_args /* { 285 struct vnode *a_vp; 286 struct uio *a_uio; 287 int a_ioflag; 288 kauth_cred_t a_cred; 289 } */ *ap = v; 290 struct uio *uio; 291 struct socket *rso; 292 int error; 293 size_t startresid; 294 295 uio = ap->a_uio; 296 rso = ap->a_vp->v_fifoinfo->fi_readsock; 297 #ifdef DIAGNOSTIC 298 if (uio->uio_rw != UIO_READ) 299 panic("fifo_read mode"); 300 #endif 301 if (uio->uio_resid == 0) 302 return (0); 303 startresid = uio->uio_resid; 304 VOP_UNLOCK(ap->a_vp, 0); 305 if (ap->a_ioflag & IO_NDELAY) { 306 /* XXX Bogus, affects other threads. */ 307 rso->so_nbio = 1; 308 } 309 error = (*rso->so_receive)(rso, NULL, uio, NULL, NULL, NULL); 310 /* 311 * Clear EOF indication after first such return. 312 */ 313 if (uio->uio_resid == startresid) 314 rso->so_state &= ~SS_CANTRCVMORE; 315 if (ap->a_ioflag & IO_NDELAY) { 316 rso->so_nbio = 0; 317 if (error == EWOULDBLOCK && 318 ap->a_vp->v_fifoinfo->fi_writers == 0) 319 error = 0; 320 } 321 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 322 return (error); 323 } 324 325 /* 326 * Vnode op for write 327 */ 328 /* ARGSUSED */ 329 int 330 fifo_write(void *v) 331 { 332 struct vop_write_args /* { 333 struct vnode *a_vp; 334 struct uio *a_uio; 335 int a_ioflag; 336 kauth_cred_t a_cred; 337 } */ *ap = v; 338 struct socket *wso; 339 int error; 340 341 wso = ap->a_vp->v_fifoinfo->fi_writesock; 342 #ifdef DIAGNOSTIC 343 if (ap->a_uio->uio_rw != UIO_WRITE) 344 panic("fifo_write mode"); 345 #endif 346 VOP_UNLOCK(ap->a_vp, 0); 347 if (ap->a_ioflag & IO_NDELAY) { 348 /* XXX Bogus, affects other threads. */ 349 wso->so_nbio = 1; 350 } 351 error = (*wso->so_send)(wso, NULL, ap->a_uio, 0, NULL, 0, curlwp); 352 if (ap->a_ioflag & IO_NDELAY) 353 wso->so_nbio = 0; 354 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 355 return (error); 356 } 357 358 /* 359 * Device ioctl operation. 360 */ 361 /* ARGSUSED */ 362 int 363 fifo_ioctl(void *v) 364 { 365 struct vop_ioctl_args /* { 366 struct vnode *a_vp; 367 u_long a_command; 368 void *a_data; 369 int a_fflag; 370 kauth_cred_t a_cred; 371 struct lwp *a_l; 372 } */ *ap = v; 373 struct file filetmp; 374 int error; 375 376 if (ap->a_command == FIONBIO) 377 return (0); 378 if (ap->a_fflag & FREAD) { 379 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_readsock; 380 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data); 381 if (error) 382 return (error); 383 } 384 if (ap->a_fflag & FWRITE) { 385 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_writesock; 386 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data); 387 if (error) 388 return (error); 389 } 390 return (0); 391 } 392 393 /* ARGSUSED */ 394 int 395 fifo_poll(void *v) 396 { 397 struct vop_poll_args /* { 398 struct vnode *a_vp; 399 int a_events; 400 struct lwp *a_l; 401 } */ *ap = v; 402 struct socket *so; 403 int revents; 404 405 revents = 0; 406 if (ap->a_events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) { 407 so = ap->a_vp->v_fifoinfo->fi_readsock; 408 if (so) 409 revents |= sopoll(so, ap->a_events); 410 } 411 if (ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND)) { 412 so = ap->a_vp->v_fifoinfo->fi_writesock; 413 if (so) 414 revents |= sopoll(so, ap->a_events); 415 } 416 417 return (revents); 418 } 419 420 int 421 fifo_inactive(void *v) 422 { 423 struct vop_inactive_args /* { 424 struct vnode *a_vp; 425 struct lwp *a_l; 426 } */ *ap = v; 427 428 VOP_UNLOCK(ap->a_vp, 0); 429 return (0); 430 } 431 432 /* 433 * This is a noop, simply returning what one has been given. 434 */ 435 int 436 fifo_bmap(void *v) 437 { 438 struct vop_bmap_args /* { 439 struct vnode *a_vp; 440 daddr_t a_bn; 441 struct vnode **a_vpp; 442 daddr_t *a_bnp; 443 int *a_runp; 444 } */ *ap = v; 445 446 if (ap->a_vpp != NULL) 447 *ap->a_vpp = ap->a_vp; 448 if (ap->a_bnp != NULL) 449 *ap->a_bnp = ap->a_bn; 450 if (ap->a_runp != NULL) 451 *ap->a_runp = 0; 452 return (0); 453 } 454 455 /* 456 * Device close routine 457 */ 458 /* ARGSUSED */ 459 int 460 fifo_close(void *v) 461 { 462 struct vop_close_args /* { 463 struct vnode *a_vp; 464 int a_fflag; 465 kauth_cred_t a_cred; 466 struct lwp *a_l; 467 } */ *ap = v; 468 struct vnode *vp; 469 struct fifoinfo *fip; 470 struct socket *wso, *rso; 471 int isrevoke; 472 473 vp = ap->a_vp; 474 fip = vp->v_fifoinfo; 475 isrevoke = (ap->a_fflag & (FREAD | FWRITE | FNONBLOCK)) == FNONBLOCK; 476 wso = fip->fi_writesock; 477 rso = fip->fi_readsock; 478 solock(wso); 479 if (isrevoke) { 480 if (fip->fi_readers != 0) { 481 fip->fi_readers = 0; 482 socantsendmore(wso); 483 } 484 if (fip->fi_writers != 0) { 485 fip->fi_writers = 0; 486 socantrcvmore(rso); 487 } 488 } else { 489 if ((ap->a_fflag & FREAD) && --fip->fi_readers == 0) 490 socantsendmore(wso); 491 if ((ap->a_fflag & FWRITE) && --fip->fi_writers == 0) 492 socantrcvmore(rso); 493 } 494 if ((fip->fi_readers + fip->fi_writers) == 0) { 495 sounlock(wso); 496 (void) soclose(rso); 497 (void) soclose(wso); 498 cv_destroy(&fip->fi_rcv); 499 cv_destroy(&fip->fi_wcv); 500 kmem_free(fip, sizeof(*fip)); 501 vp->v_fifoinfo = NULL; 502 } else 503 sounlock(wso); 504 return (0); 505 } 506 507 /* 508 * Print out the contents of a fifo vnode. 509 */ 510 int 511 fifo_print(void *v) 512 { 513 struct vop_print_args /* { 514 struct vnode *a_vp; 515 } */ *ap = v; 516 517 printf("tag VT_NON"); 518 fifo_printinfo(ap->a_vp); 519 printf("\n"); 520 return 0; 521 } 522 523 /* 524 * Print out internal contents of a fifo vnode. 525 */ 526 void 527 fifo_printinfo(struct vnode *vp) 528 { 529 struct fifoinfo *fip; 530 531 fip = vp->v_fifoinfo; 532 printf(", fifo with %d readers and %d writers", 533 fip->fi_readers, fip->fi_writers); 534 } 535 536 /* 537 * Return POSIX pathconf information applicable to fifo's. 538 */ 539 int 540 fifo_pathconf(void *v) 541 { 542 struct vop_pathconf_args /* { 543 struct vnode *a_vp; 544 int a_name; 545 register_t *a_retval; 546 } */ *ap = v; 547 548 switch (ap->a_name) { 549 case _PC_LINK_MAX: 550 *ap->a_retval = LINK_MAX; 551 return (0); 552 case _PC_PIPE_BUF: 553 *ap->a_retval = PIPE_BUF; 554 return (0); 555 case _PC_CHOWN_RESTRICTED: 556 *ap->a_retval = 1; 557 return (0); 558 case _PC_SYNC_IO: 559 *ap->a_retval = 1; 560 return (0); 561 default: 562 return (EINVAL); 563 } 564 /* NOTREACHED */ 565 } 566 567 static void 568 filt_fifordetach(struct knote *kn) 569 { 570 struct socket *so; 571 572 so = (struct socket *)kn->kn_hook; 573 solock(so); 574 SLIST_REMOVE(&so->so_rcv.sb_sel.sel_klist, kn, knote, kn_selnext); 575 if (SLIST_EMPTY(&so->so_rcv.sb_sel.sel_klist)) 576 so->so_rcv.sb_flags &= ~SB_KNOTE; 577 sounlock(so); 578 } 579 580 static int 581 filt_fiforead(struct knote *kn, long hint) 582 { 583 struct socket *so; 584 int rv; 585 586 so = (struct socket *)kn->kn_hook; 587 if (hint != NOTE_SUBMIT) 588 solock(so); 589 kn->kn_data = so->so_rcv.sb_cc; 590 if (so->so_state & SS_CANTRCVMORE) { 591 kn->kn_flags |= EV_EOF; 592 rv = 1; 593 } else { 594 kn->kn_flags &= ~EV_EOF; 595 rv = (kn->kn_data > 0); 596 } 597 if (hint != NOTE_SUBMIT) 598 sounlock(so); 599 return rv; 600 } 601 602 static void 603 filt_fifowdetach(struct knote *kn) 604 { 605 struct socket *so; 606 607 so = (struct socket *)kn->kn_hook; 608 solock(so); 609 SLIST_REMOVE(&so->so_snd.sb_sel.sel_klist, kn, knote, kn_selnext); 610 if (SLIST_EMPTY(&so->so_snd.sb_sel.sel_klist)) 611 so->so_snd.sb_flags &= ~SB_KNOTE; 612 sounlock(so); 613 } 614 615 static int 616 filt_fifowrite(struct knote *kn, long hint) 617 { 618 struct socket *so; 619 int rv; 620 621 so = (struct socket *)kn->kn_hook; 622 if (hint != NOTE_SUBMIT) 623 solock(so); 624 kn->kn_data = sbspace(&so->so_snd); 625 if (so->so_state & SS_CANTSENDMORE) { 626 kn->kn_flags |= EV_EOF; 627 rv = 1; 628 } else { 629 kn->kn_flags &= ~EV_EOF; 630 rv = (kn->kn_data >= so->so_snd.sb_lowat); 631 } 632 if (hint != NOTE_SUBMIT) 633 sounlock(so); 634 return rv; 635 } 636 637 static const struct filterops fiforead_filtops = 638 { 1, NULL, filt_fifordetach, filt_fiforead }; 639 static const struct filterops fifowrite_filtops = 640 { 1, NULL, filt_fifowdetach, filt_fifowrite }; 641 642 /* ARGSUSED */ 643 int 644 fifo_kqfilter(void *v) 645 { 646 struct vop_kqfilter_args /* { 647 struct vnode *a_vp; 648 struct knote *a_kn; 649 } */ *ap = v; 650 struct socket *so; 651 struct sockbuf *sb; 652 653 so = (struct socket *)ap->a_vp->v_fifoinfo->fi_readsock; 654 switch (ap->a_kn->kn_filter) { 655 case EVFILT_READ: 656 ap->a_kn->kn_fop = &fiforead_filtops; 657 sb = &so->so_rcv; 658 break; 659 case EVFILT_WRITE: 660 ap->a_kn->kn_fop = &fifowrite_filtops; 661 sb = &so->so_snd; 662 break; 663 default: 664 return (EINVAL); 665 } 666 667 ap->a_kn->kn_hook = so; 668 669 solock(so); 670 SLIST_INSERT_HEAD(&sb->sb_sel.sel_klist, ap->a_kn, kn_selnext); 671 sb->sb_flags |= SB_KNOTE; 672 sounlock(so); 673 674 return (0); 675 } 676