1 /* $OpenBSD: fifo_vnops.c,v 1.109 2024/12/30 02:46:00 guenther Exp $ */ 2 /* $NetBSD: fifo_vnops.c,v 1.18 1996/03/16 23:52:42 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1990, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)fifo_vnops.c 8.4 (Berkeley) 8/10/94 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/time.h> 38 #include <sys/namei.h> 39 #include <sys/vnode.h> 40 #include <sys/lock.h> 41 #include <sys/protosw.h> 42 #include <sys/socket.h> 43 #include <sys/socketvar.h> 44 #include <sys/stat.h> 45 #include <sys/ioctl.h> 46 #include <sys/fcntl.h> 47 #include <sys/file.h> 48 #include <sys/event.h> 49 #include <sys/errno.h> 50 #include <sys/malloc.h> 51 #include <sys/unistd.h> 52 53 #include <miscfs/fifofs/fifo.h> 54 55 /* 56 * This structure is associated with the FIFO vnode and stores 57 * the state associated with the FIFO. 58 */ 59 struct fifoinfo { 60 struct socket *fi_readsock; 61 struct socket *fi_writesock; 62 long fi_readers; 63 long fi_writers; 64 }; 65 66 const struct vops fifo_vops = { 67 .vop_lookup = vop_generic_lookup, 68 .vop_create = vop_generic_badop, 69 .vop_mknod = vop_generic_badop, 70 .vop_open = fifo_open, 71 .vop_close = fifo_close, 72 .vop_access = fifo_ebadf, 73 .vop_getattr = fifo_ebadf, 74 .vop_setattr = fifo_ebadf, 75 .vop_read = fifo_read, 76 .vop_write = fifo_write, 77 .vop_ioctl = fifo_ioctl, 78 .vop_kqfilter = fifo_kqfilter, 79 .vop_revoke = vop_generic_revoke, 80 .vop_fsync = nullop, 81 .vop_remove = vop_generic_badop, 82 .vop_link = vop_generic_badop, 83 .vop_rename = vop_generic_badop, 84 .vop_mkdir = vop_generic_badop, 85 .vop_rmdir = vop_generic_badop, 86 .vop_symlink = vop_generic_badop, 87 .vop_readdir = vop_generic_badop, 88 .vop_readlink = vop_generic_badop, 89 .vop_abortop = vop_generic_badop, 90 .vop_inactive = fifo_inactive, 91 .vop_reclaim = fifo_reclaim, 92 .vop_lock = nullop, 93 .vop_unlock = nullop, 94 .vop_islocked = nullop, 95 .vop_bmap = vop_generic_bmap, 96 .vop_strategy = vop_generic_badop, 97 .vop_print = fifo_print, 98 .vop_pathconf = fifo_pathconf, 99 .vop_advlock = fifo_advlock, 100 .vop_bwrite = nullop 101 }; 102 103 void filt_fifordetach(struct knote *kn); 104 int filt_fiforead(struct knote *kn, long hint); 105 void filt_fifowdetach(struct knote *kn); 106 int filt_fifowrite(struct knote *kn, long hint); 107 int filt_fifoexcept(struct knote *kn, long hint); 108 int filt_fiformodify(struct kevent *kev, struct knote *kn); 109 int filt_fiforprocess(struct knote *kn, struct kevent *kev); 110 int filt_fifowmodify(struct kevent *kev, struct knote *kn); 111 int filt_fifowprocess(struct knote *kn, struct kevent *kev); 112 113 const struct filterops fiforead_filtops = { 114 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, 115 .f_attach = NULL, 116 .f_detach = filt_fifordetach, 117 .f_event = filt_fiforead, 118 .f_modify = filt_fiformodify, 119 .f_process = filt_fiforprocess, 120 }; 121 122 const struct filterops fifowrite_filtops = { 123 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, 124 .f_attach = NULL, 125 .f_detach = filt_fifowdetach, 126 .f_event = filt_fifowrite, 127 .f_modify = filt_fifowmodify, 128 .f_process = filt_fifowprocess, 129 }; 130 131 const struct filterops fifoexcept_filtops = { 132 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, 133 .f_attach = NULL, 134 .f_detach = filt_fifordetach, 135 .f_event = filt_fifoexcept, 136 .f_modify = filt_fiformodify, 137 .f_process = filt_fiforprocess, 138 }; 139 140 /* 141 * Open called to set up a new instance of a fifo or 142 * to find an active instance of a fifo. 143 */ 144 int 145 fifo_open(void *v) 146 { 147 struct vop_open_args *ap = v; 148 struct vnode *vp = ap->a_vp; 149 struct fifoinfo *fip; 150 struct socket *rso, *wso; 151 int error; 152 153 if ((fip = vp->v_fifoinfo) == NULL) { 154 fip = malloc(sizeof(*fip), M_VNODE, M_WAITOK); 155 vp->v_fifoinfo = fip; 156 if ((error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0)) != 0) { 157 free(fip, M_VNODE, sizeof *fip); 158 vp->v_fifoinfo = NULL; 159 return (error); 160 } 161 fip->fi_readsock = rso; 162 if ((error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0)) != 0) { 163 (void)soclose(rso, 0); 164 free(fip, M_VNODE, sizeof *fip); 165 vp->v_fifoinfo = NULL; 166 return (error); 167 } 168 fip->fi_writesock = wso; 169 if ((error = soconnect2(wso, rso)) != 0) { 170 (void)soclose(wso, 0); 171 (void)soclose(rso, 0); 172 free(fip, M_VNODE, sizeof *fip); 173 vp->v_fifoinfo = NULL; 174 return (error); 175 } 176 fip->fi_readers = fip->fi_writers = 0; 177 /* 178 * Should take both solock() and `sb_mtx' mutex for 179 * SS_CANTSENDMORE flag modifications. 180 */ 181 solock(wso); 182 mtx_enter(&wso->so_snd.sb_mtx); 183 wso->so_snd.sb_state |= SS_CANTSENDMORE; 184 wso->so_snd.sb_lowat = PIPE_BUF; 185 mtx_leave(&wso->so_snd.sb_mtx); 186 sounlock(wso); 187 } else { 188 rso = fip->fi_readsock; 189 wso = fip->fi_writesock; 190 } 191 if (ap->a_mode & FREAD) { 192 fip->fi_readers++; 193 if (fip->fi_readers == 1) { 194 solock(wso); 195 mtx_enter(&wso->so_snd.sb_mtx); 196 wso->so_snd.sb_state &= ~SS_CANTSENDMORE; 197 mtx_leave(&wso->so_snd.sb_mtx); 198 sounlock(wso); 199 if (fip->fi_writers > 0) 200 wakeup(&fip->fi_writers); 201 } 202 } 203 if (ap->a_mode & FWRITE) { 204 fip->fi_writers++; 205 if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) { 206 error = ENXIO; 207 goto bad; 208 } 209 if (fip->fi_writers == 1) { 210 solock(rso); 211 rso->so_state &= ~SS_ISDISCONNECTED; 212 mtx_enter(&rso->so_rcv.sb_mtx); 213 rso->so_rcv.sb_state &= ~SS_CANTRCVMORE; 214 mtx_leave(&rso->so_rcv.sb_mtx); 215 sounlock(rso); 216 if (fip->fi_readers > 0) 217 wakeup(&fip->fi_readers); 218 } 219 } 220 if ((ap->a_mode & O_NONBLOCK) == 0) { 221 if ((ap->a_mode & FREAD) && fip->fi_writers == 0) { 222 VOP_UNLOCK(vp); 223 error = tsleep_nsec(&fip->fi_readers, 224 PCATCH | PSOCK, "fifor", INFSLP); 225 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 226 if (error) 227 goto bad; 228 } 229 if ((ap->a_mode & FWRITE) && fip->fi_readers == 0) { 230 VOP_UNLOCK(vp); 231 error = tsleep_nsec(&fip->fi_writers, 232 PCATCH | PSOCK, "fifow", INFSLP); 233 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 234 if (error) 235 goto bad; 236 } 237 } 238 return (0); 239 bad: 240 VOP_CLOSE(vp, ap->a_mode, ap->a_cred, ap->a_p); 241 return (error); 242 } 243 244 /* 245 * Vnode op for read 246 */ 247 int 248 fifo_read(void *v) 249 { 250 struct vop_read_args *ap = v; 251 struct uio *uio = ap->a_uio; 252 struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock; 253 int error, flags = 0; 254 255 #ifdef DIAGNOSTIC 256 if (uio->uio_rw != UIO_READ) 257 panic("fifo_read mode"); 258 #endif 259 if (uio->uio_resid == 0) 260 return (0); 261 if (ap->a_ioflag & IO_NDELAY) 262 flags |= MSG_DONTWAIT; 263 VOP_UNLOCK(ap->a_vp); 264 error = soreceive(rso, NULL, uio, NULL, NULL, &flags, 0); 265 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 266 if (ap->a_ioflag & IO_NDELAY) { 267 if (error == EWOULDBLOCK && 268 ap->a_vp->v_fifoinfo->fi_writers == 0) 269 error = 0; 270 } 271 return (error); 272 } 273 274 /* 275 * Vnode op for write 276 */ 277 int 278 fifo_write(void *v) 279 { 280 struct vop_write_args *ap = v; 281 struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock; 282 int error, flags = 0; 283 284 #ifdef DIAGNOSTIC 285 if (ap->a_uio->uio_rw != UIO_WRITE) 286 panic("fifo_write mode"); 287 #endif 288 if (ap->a_ioflag & IO_NDELAY) 289 flags |= MSG_DONTWAIT; 290 VOP_UNLOCK(ap->a_vp); 291 error = sosend(wso, NULL, ap->a_uio, NULL, NULL, flags); 292 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 293 return (error); 294 } 295 296 /* 297 * Device ioctl operation. 298 */ 299 int 300 fifo_ioctl(void *v) 301 { 302 struct vop_ioctl_args *ap = v; 303 struct file filetmp; 304 int error; 305 306 if (ap->a_fflag & FREAD) { 307 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_readsock; 308 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p); 309 if (error) 310 return (error); 311 } 312 if (ap->a_fflag & FWRITE) { 313 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_writesock; 314 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p); 315 if (error) 316 return (error); 317 } 318 return (0); 319 } 320 321 int 322 fifo_inactive(void *v) 323 { 324 struct vop_inactive_args *ap = v; 325 326 VOP_UNLOCK(ap->a_vp); 327 return (0); 328 } 329 330 331 /* 332 * Device close routine 333 */ 334 int 335 fifo_close(void *v) 336 { 337 struct vop_close_args *ap = v; 338 struct vnode *vp = ap->a_vp; 339 struct fifoinfo *fip = vp->v_fifoinfo; 340 int error1 = 0, error2 = 0; 341 342 if (fip == NULL) 343 return (0); 344 345 if (ap->a_fflag & FREAD) { 346 if (--fip->fi_readers == 0) { 347 struct socket *wso = fip->fi_writesock; 348 349 solock(wso); 350 socantsendmore(wso); 351 sounlock(wso); 352 } 353 } 354 if (ap->a_fflag & FWRITE) { 355 if (--fip->fi_writers == 0) { 356 struct socket *rso = fip->fi_readsock; 357 358 solock(rso); 359 /* SS_ISDISCONNECTED will result in POLLHUP */ 360 rso->so_state |= SS_ISDISCONNECTED; 361 socantrcvmore(rso); 362 sounlock(rso); 363 } 364 } 365 if (fip->fi_readers == 0 && fip->fi_writers == 0) { 366 error1 = soclose(fip->fi_readsock, 0); 367 error2 = soclose(fip->fi_writesock, 0); 368 free(fip, M_VNODE, sizeof *fip); 369 vp->v_fifoinfo = NULL; 370 } 371 return (error1 ? error1 : error2); 372 } 373 374 int 375 fifo_reclaim(void *v) 376 { 377 struct vop_reclaim_args *ap = v; 378 struct vnode *vp = ap->a_vp; 379 struct fifoinfo *fip = vp->v_fifoinfo; 380 381 if (fip == NULL) 382 return (0); 383 384 soclose(fip->fi_readsock, 0); 385 soclose(fip->fi_writesock, 0); 386 free(fip, M_VNODE, sizeof *fip); 387 vp->v_fifoinfo = NULL; 388 389 return (0); 390 } 391 392 /* 393 * Print out the contents of a fifo vnode. 394 */ 395 int 396 fifo_print(void *v) 397 { 398 #if defined(DEBUG) || defined(DIAGNOSTIC) || defined(VFSLCKDEBUG) 399 struct vop_print_args *ap = v; 400 401 printf("tag VT_NON"); 402 fifo_printinfo(ap->a_vp); 403 printf("\n"); 404 #endif 405 return 0; 406 } 407 408 #if defined(DEBUG) || defined(DIAGNOSTIC) || defined(VFSLCKDEBUG) 409 /* 410 * Print out internal contents of a fifo vnode. 411 */ 412 void 413 fifo_printinfo(struct vnode *vp) 414 { 415 struct fifoinfo *fip = vp->v_fifoinfo; 416 417 printf(", fifo with %ld readers and %ld writers", 418 fip->fi_readers, fip->fi_writers); 419 } 420 #endif 421 422 /* 423 * Return POSIX pathconf information applicable to fifo's. 424 */ 425 int 426 fifo_pathconf(void *v) 427 { 428 struct vop_pathconf_args *ap = v; 429 int error = 0; 430 431 switch (ap->a_name) { 432 case _PC_LINK_MAX: 433 *ap->a_retval = LINK_MAX; 434 break; 435 case _PC_CHOWN_RESTRICTED: 436 *ap->a_retval = 1; 437 break; 438 case _PC_TIMESTAMP_RESOLUTION: 439 *ap->a_retval = 1; 440 break; 441 default: 442 error = EINVAL; 443 break; 444 } 445 446 return (error); 447 } 448 449 /* 450 * Fifo failed operation 451 */ 452 int 453 fifo_ebadf(void *v) 454 { 455 456 return (EBADF); 457 } 458 459 /* 460 * Fifo advisory byte-level locks. 461 */ 462 int 463 fifo_advlock(void *v) 464 { 465 return (EOPNOTSUPP); 466 } 467 468 int 469 fifo_kqfilter(void *v) 470 { 471 struct vop_kqfilter_args *ap = v; 472 struct fifoinfo *fip = ap->a_vp->v_fifoinfo; 473 struct sockbuf *sb; 474 struct socket *so; 475 476 switch (ap->a_kn->kn_filter) { 477 case EVFILT_READ: 478 if (!(ap->a_fflag & FREAD)) 479 return (EINVAL); 480 ap->a_kn->kn_fop = &fiforead_filtops; 481 so = fip->fi_readsock; 482 sb = &so->so_rcv; 483 break; 484 case EVFILT_WRITE: 485 if (!(ap->a_fflag & FWRITE)) { 486 /* Tell upper layer to ask for POLLUP only */ 487 if (ap->a_kn->kn_flags & (__EV_POLL | __EV_SELECT)) 488 return (EPERM); 489 return (EINVAL); 490 } 491 ap->a_kn->kn_fop = &fifowrite_filtops; 492 so = fip->fi_writesock; 493 sb = &so->so_snd; 494 break; 495 case EVFILT_EXCEPT: 496 if (ap->a_kn->kn_flags & __EV_SELECT) { 497 /* Prevent triggering exceptfds. */ 498 return (EPERM); 499 } 500 if ((ap->a_kn->kn_flags & __EV_POLL) == 0) { 501 /* Disallow usage through kevent(2). */ 502 return (EINVAL); 503 } 504 ap->a_kn->kn_fop = &fifoexcept_filtops; 505 so = fip->fi_readsock; 506 sb = &so->so_rcv; 507 break; 508 default: 509 return (EINVAL); 510 } 511 512 ap->a_kn->kn_hook = so; 513 514 klist_insert(&sb->sb_klist, ap->a_kn); 515 516 return (0); 517 } 518 519 void 520 filt_fifordetach(struct knote *kn) 521 { 522 struct socket *so = (struct socket *)kn->kn_hook; 523 524 klist_remove(&so->so_rcv.sb_klist, kn); 525 } 526 527 int 528 filt_fiforead(struct knote *kn, long hint) 529 { 530 struct socket *so = kn->kn_hook; 531 int rv; 532 533 MUTEX_ASSERT_LOCKED(&so->so_rcv.sb_mtx); 534 535 kn->kn_data = so->so_rcv.sb_cc; 536 if (so->so_rcv.sb_state & SS_CANTRCVMORE) { 537 kn->kn_flags |= EV_EOF; 538 if (kn->kn_flags & __EV_POLL) { 539 if (so->so_state & SS_ISDISCONNECTED) 540 kn->kn_flags |= __EV_HUP; 541 else 542 kn->kn_flags &= ~__EV_HUP; 543 } 544 rv = 1; 545 } else { 546 kn->kn_flags &= ~(EV_EOF | __EV_HUP); 547 rv = (kn->kn_data > 0); 548 } 549 550 return (rv); 551 } 552 553 void 554 filt_fifowdetach(struct knote *kn) 555 { 556 struct socket *so = (struct socket *)kn->kn_hook; 557 558 klist_remove(&so->so_snd.sb_klist, kn); 559 } 560 561 int 562 filt_fifowrite(struct knote *kn, long hint) 563 { 564 struct socket *so = kn->kn_hook; 565 int rv; 566 567 MUTEX_ASSERT_LOCKED(&so->so_snd.sb_mtx); 568 569 kn->kn_data = sbspace_locked(so, &so->so_snd); 570 if (so->so_snd.sb_state & SS_CANTSENDMORE) { 571 kn->kn_flags |= EV_EOF; 572 rv = 1; 573 } else { 574 kn->kn_flags &= ~EV_EOF; 575 rv = (kn->kn_data >= so->so_snd.sb_lowat); 576 } 577 578 return (rv); 579 } 580 581 int 582 filt_fifoexcept(struct knote *kn, long hint) 583 { 584 struct socket *so = kn->kn_hook; 585 int rv = 0; 586 587 MUTEX_ASSERT_LOCKED(&so->so_rcv.sb_mtx); 588 589 if (kn->kn_flags & __EV_POLL) { 590 if (so->so_state & SS_ISDISCONNECTED) { 591 kn->kn_flags |= __EV_HUP; 592 rv = 1; 593 } else { 594 kn->kn_flags &= ~__EV_HUP; 595 } 596 } 597 598 return (rv); 599 } 600 601 int 602 filt_fiformodify(struct kevent *kev, struct knote *kn) 603 { 604 struct socket *so = kn->kn_hook; 605 int rv; 606 607 solock(so); 608 mtx_enter(&so->so_rcv.sb_mtx); 609 rv = knote_modify(kev, kn); 610 mtx_leave(&so->so_rcv.sb_mtx); 611 sounlock(so); 612 613 return (rv); 614 } 615 616 int 617 filt_fiforprocess(struct knote *kn, struct kevent *kev) 618 { 619 struct socket *so = kn->kn_hook; 620 int rv; 621 622 solock(so); 623 mtx_enter(&so->so_rcv.sb_mtx); 624 rv = knote_process(kn, kev); 625 mtx_leave(&so->so_rcv.sb_mtx); 626 sounlock(so); 627 628 return (rv); 629 } 630 631 int 632 filt_fifowmodify(struct kevent *kev, struct knote *kn) 633 { 634 struct socket *so = kn->kn_hook; 635 int rv; 636 637 mtx_enter(&so->so_snd.sb_mtx); 638 rv = knote_modify(kev, kn); 639 mtx_leave(&so->so_snd.sb_mtx); 640 641 return (rv); 642 } 643 644 int 645 filt_fifowprocess(struct knote *kn, struct kevent *kev) 646 { 647 struct socket *so = kn->kn_hook; 648 int rv; 649 650 mtx_enter(&so->so_snd.sb_mtx); 651 rv = knote_process(kn, kev); 652 mtx_leave(&so->so_snd.sb_mtx); 653 654 return (rv); 655 } 656