1 /* $OpenBSD: fifo_vnops.c,v 1.107 2024/07/12 17:20:18 mvs 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_command == FIONBIO) 307 return (0); 308 if (ap->a_fflag & FREAD) { 309 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_readsock; 310 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p); 311 if (error) 312 return (error); 313 } 314 if (ap->a_fflag & FWRITE) { 315 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_writesock; 316 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p); 317 if (error) 318 return (error); 319 } 320 return (0); 321 } 322 323 int 324 fifo_inactive(void *v) 325 { 326 struct vop_inactive_args *ap = v; 327 328 VOP_UNLOCK(ap->a_vp); 329 return (0); 330 } 331 332 333 /* 334 * Device close routine 335 */ 336 int 337 fifo_close(void *v) 338 { 339 struct vop_close_args *ap = v; 340 struct vnode *vp = ap->a_vp; 341 struct fifoinfo *fip = vp->v_fifoinfo; 342 int error1 = 0, error2 = 0; 343 344 if (fip == NULL) 345 return (0); 346 347 if (ap->a_fflag & FREAD) { 348 if (--fip->fi_readers == 0) { 349 struct socket *wso = fip->fi_writesock; 350 351 solock(wso); 352 socantsendmore(wso); 353 sounlock(wso); 354 } 355 } 356 if (ap->a_fflag & FWRITE) { 357 if (--fip->fi_writers == 0) { 358 struct socket *rso = fip->fi_readsock; 359 360 solock(rso); 361 /* SS_ISDISCONNECTED will result in POLLHUP */ 362 rso->so_state |= SS_ISDISCONNECTED; 363 socantrcvmore(rso); 364 sounlock(rso); 365 } 366 } 367 if (fip->fi_readers == 0 && fip->fi_writers == 0) { 368 error1 = soclose(fip->fi_readsock, 0); 369 error2 = soclose(fip->fi_writesock, 0); 370 free(fip, M_VNODE, sizeof *fip); 371 vp->v_fifoinfo = NULL; 372 } 373 return (error1 ? error1 : error2); 374 } 375 376 int 377 fifo_reclaim(void *v) 378 { 379 struct vop_reclaim_args *ap = v; 380 struct vnode *vp = ap->a_vp; 381 struct fifoinfo *fip = vp->v_fifoinfo; 382 383 if (fip == NULL) 384 return (0); 385 386 soclose(fip->fi_readsock, 0); 387 soclose(fip->fi_writesock, 0); 388 free(fip, M_VNODE, sizeof *fip); 389 vp->v_fifoinfo = NULL; 390 391 return (0); 392 } 393 394 /* 395 * Print out the contents of a fifo vnode. 396 */ 397 int 398 fifo_print(void *v) 399 { 400 struct vop_print_args *ap = v; 401 402 printf("tag VT_NON"); 403 fifo_printinfo(ap->a_vp); 404 printf("\n"); 405 return 0; 406 } 407 408 /* 409 * Print out internal contents of a fifo vnode. 410 */ 411 void 412 fifo_printinfo(struct vnode *vp) 413 { 414 struct fifoinfo *fip = vp->v_fifoinfo; 415 416 printf(", fifo with %ld readers and %ld writers", 417 fip->fi_readers, fip->fi_writers); 418 } 419 420 /* 421 * Return POSIX pathconf information applicable to fifo's. 422 */ 423 int 424 fifo_pathconf(void *v) 425 { 426 struct vop_pathconf_args *ap = v; 427 int error = 0; 428 429 switch (ap->a_name) { 430 case _PC_LINK_MAX: 431 *ap->a_retval = LINK_MAX; 432 break; 433 case _PC_CHOWN_RESTRICTED: 434 *ap->a_retval = 1; 435 break; 436 case _PC_TIMESTAMP_RESOLUTION: 437 *ap->a_retval = 1; 438 break; 439 default: 440 error = EINVAL; 441 break; 442 } 443 444 return (error); 445 } 446 447 /* 448 * Fifo failed operation 449 */ 450 int 451 fifo_ebadf(void *v) 452 { 453 454 return (EBADF); 455 } 456 457 /* 458 * Fifo advisory byte-level locks. 459 */ 460 int 461 fifo_advlock(void *v) 462 { 463 return (EOPNOTSUPP); 464 } 465 466 int 467 fifo_kqfilter(void *v) 468 { 469 struct vop_kqfilter_args *ap = v; 470 struct fifoinfo *fip = ap->a_vp->v_fifoinfo; 471 struct sockbuf *sb; 472 struct socket *so; 473 474 switch (ap->a_kn->kn_filter) { 475 case EVFILT_READ: 476 if (!(ap->a_fflag & FREAD)) 477 return (EINVAL); 478 ap->a_kn->kn_fop = &fiforead_filtops; 479 so = fip->fi_readsock; 480 sb = &so->so_rcv; 481 break; 482 case EVFILT_WRITE: 483 if (!(ap->a_fflag & FWRITE)) { 484 /* Tell upper layer to ask for POLLUP only */ 485 if (ap->a_kn->kn_flags & (__EV_POLL | __EV_SELECT)) 486 return (EPERM); 487 return (EINVAL); 488 } 489 ap->a_kn->kn_fop = &fifowrite_filtops; 490 so = fip->fi_writesock; 491 sb = &so->so_snd; 492 break; 493 case EVFILT_EXCEPT: 494 if (ap->a_kn->kn_flags & __EV_SELECT) { 495 /* Prevent triggering exceptfds. */ 496 return (EPERM); 497 } 498 if ((ap->a_kn->kn_flags & __EV_POLL) == 0) { 499 /* Disallow usage through kevent(2). */ 500 return (EINVAL); 501 } 502 ap->a_kn->kn_fop = &fifoexcept_filtops; 503 so = fip->fi_readsock; 504 sb = &so->so_rcv; 505 break; 506 default: 507 return (EINVAL); 508 } 509 510 ap->a_kn->kn_hook = so; 511 512 klist_insert(&sb->sb_klist, ap->a_kn); 513 514 return (0); 515 } 516 517 void 518 filt_fifordetach(struct knote *kn) 519 { 520 struct socket *so = (struct socket *)kn->kn_hook; 521 522 klist_remove(&so->so_rcv.sb_klist, kn); 523 } 524 525 int 526 filt_fiforead(struct knote *kn, long hint) 527 { 528 struct socket *so = kn->kn_hook; 529 int rv; 530 531 MUTEX_ASSERT_LOCKED(&so->so_rcv.sb_mtx); 532 533 kn->kn_data = so->so_rcv.sb_cc; 534 if (so->so_rcv.sb_state & SS_CANTRCVMORE) { 535 kn->kn_flags |= EV_EOF; 536 if (kn->kn_flags & __EV_POLL) { 537 if (so->so_state & SS_ISDISCONNECTED) 538 kn->kn_flags |= __EV_HUP; 539 else 540 kn->kn_flags &= ~__EV_HUP; 541 } 542 rv = 1; 543 } else { 544 kn->kn_flags &= ~(EV_EOF | __EV_HUP); 545 rv = (kn->kn_data > 0); 546 } 547 548 return (rv); 549 } 550 551 void 552 filt_fifowdetach(struct knote *kn) 553 { 554 struct socket *so = (struct socket *)kn->kn_hook; 555 556 klist_remove(&so->so_snd.sb_klist, kn); 557 } 558 559 int 560 filt_fifowrite(struct knote *kn, long hint) 561 { 562 struct socket *so = kn->kn_hook; 563 int rv; 564 565 MUTEX_ASSERT_LOCKED(&so->so_snd.sb_mtx); 566 567 kn->kn_data = sbspace_locked(so, &so->so_snd); 568 if (so->so_snd.sb_state & SS_CANTSENDMORE) { 569 kn->kn_flags |= EV_EOF; 570 rv = 1; 571 } else { 572 kn->kn_flags &= ~EV_EOF; 573 rv = (kn->kn_data >= so->so_snd.sb_lowat); 574 } 575 576 return (rv); 577 } 578 579 int 580 filt_fifoexcept(struct knote *kn, long hint) 581 { 582 struct socket *so = kn->kn_hook; 583 int rv = 0; 584 585 MUTEX_ASSERT_LOCKED(&so->so_rcv.sb_mtx); 586 587 if (kn->kn_flags & __EV_POLL) { 588 if (so->so_state & SS_ISDISCONNECTED) { 589 kn->kn_flags |= __EV_HUP; 590 rv = 1; 591 } else { 592 kn->kn_flags &= ~__EV_HUP; 593 } 594 } 595 596 return (rv); 597 } 598 599 int 600 filt_fiformodify(struct kevent *kev, struct knote *kn) 601 { 602 struct socket *so = kn->kn_hook; 603 int rv; 604 605 solock(so); 606 mtx_enter(&so->so_rcv.sb_mtx); 607 rv = knote_modify(kev, kn); 608 mtx_leave(&so->so_rcv.sb_mtx); 609 sounlock(so); 610 611 return (rv); 612 } 613 614 int 615 filt_fiforprocess(struct knote *kn, struct kevent *kev) 616 { 617 struct socket *so = kn->kn_hook; 618 int rv; 619 620 solock(so); 621 mtx_enter(&so->so_rcv.sb_mtx); 622 rv = knote_process(kn, kev); 623 mtx_leave(&so->so_rcv.sb_mtx); 624 sounlock(so); 625 626 return (rv); 627 } 628 629 int 630 filt_fifowmodify(struct kevent *kev, struct knote *kn) 631 { 632 struct socket *so = kn->kn_hook; 633 int rv; 634 635 mtx_enter(&so->so_snd.sb_mtx); 636 rv = knote_modify(kev, kn); 637 mtx_leave(&so->so_snd.sb_mtx); 638 639 return (rv); 640 } 641 642 int 643 filt_fifowprocess(struct knote *kn, struct kevent *kev) 644 { 645 struct socket *so = kn->kn_hook; 646 int rv; 647 648 mtx_enter(&so->so_snd.sb_mtx); 649 rv = knote_process(kn, kev); 650 mtx_leave(&so->so_snd.sb_mtx); 651 652 return (rv); 653 } 654