1 /* $OpenBSD: fifo_vnops.c,v 1.100 2023/01/22 12:05:44 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_fifomodify(struct kevent *kev, struct knote *kn); 109 int filt_fifoprocess(struct knote *kn, struct kevent *kev); 110 111 const struct filterops fiforead_filtops = { 112 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, 113 .f_attach = NULL, 114 .f_detach = filt_fifordetach, 115 .f_event = filt_fiforead, 116 .f_modify = filt_fifomodify, 117 .f_process = filt_fifoprocess, 118 }; 119 120 const struct filterops fifowrite_filtops = { 121 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, 122 .f_attach = NULL, 123 .f_detach = filt_fifowdetach, 124 .f_event = filt_fifowrite, 125 .f_modify = filt_fifomodify, 126 .f_process = filt_fifoprocess, 127 }; 128 129 const struct filterops fifoexcept_filtops = { 130 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, 131 .f_attach = NULL, 132 .f_detach = filt_fifordetach, 133 .f_event = filt_fifoexcept, 134 .f_modify = filt_fifomodify, 135 .f_process = filt_fifoprocess, 136 }; 137 138 /* 139 * Open called to set up a new instance of a fifo or 140 * to find an active instance of a fifo. 141 */ 142 /* ARGSUSED */ 143 int 144 fifo_open(void *v) 145 { 146 struct vop_open_args *ap = v; 147 struct vnode *vp = ap->a_vp; 148 struct fifoinfo *fip; 149 struct socket *rso, *wso; 150 int error; 151 152 if ((fip = vp->v_fifoinfo) == NULL) { 153 fip = malloc(sizeof(*fip), M_VNODE, M_WAITOK); 154 vp->v_fifoinfo = fip; 155 if ((error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0)) != 0) { 156 free(fip, M_VNODE, sizeof *fip); 157 vp->v_fifoinfo = NULL; 158 return (error); 159 } 160 fip->fi_readsock = rso; 161 if ((error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0)) != 0) { 162 (void)soclose(rso, 0); 163 free(fip, M_VNODE, sizeof *fip); 164 vp->v_fifoinfo = NULL; 165 return (error); 166 } 167 fip->fi_writesock = wso; 168 if ((error = soconnect2(wso, rso)) != 0) { 169 (void)soclose(wso, 0); 170 (void)soclose(rso, 0); 171 free(fip, M_VNODE, sizeof *fip); 172 vp->v_fifoinfo = NULL; 173 return (error); 174 } 175 fip->fi_readers = fip->fi_writers = 0; 176 solock(wso); 177 wso->so_snd.sb_state |= SS_CANTSENDMORE; 178 wso->so_snd.sb_lowat = PIPE_BUF; 179 sounlock(wso); 180 } else { 181 rso = fip->fi_readsock; 182 wso = fip->fi_writesock; 183 } 184 if (ap->a_mode & FREAD) { 185 fip->fi_readers++; 186 if (fip->fi_readers == 1) { 187 solock(wso); 188 wso->so_snd.sb_state &= ~SS_CANTSENDMORE; 189 sounlock(wso); 190 if (fip->fi_writers > 0) 191 wakeup(&fip->fi_writers); 192 } 193 } 194 if (ap->a_mode & FWRITE) { 195 fip->fi_writers++; 196 if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) { 197 error = ENXIO; 198 goto bad; 199 } 200 if (fip->fi_writers == 1) { 201 solock(rso); 202 rso->so_state &= ~SS_ISDISCONNECTED; 203 rso->so_rcv.sb_state &= ~SS_CANTRCVMORE; 204 sounlock(rso); 205 if (fip->fi_readers > 0) 206 wakeup(&fip->fi_readers); 207 } 208 } 209 if ((ap->a_mode & O_NONBLOCK) == 0) { 210 if ((ap->a_mode & FREAD) && fip->fi_writers == 0) { 211 VOP_UNLOCK(vp); 212 error = tsleep_nsec(&fip->fi_readers, 213 PCATCH | PSOCK, "fifor", INFSLP); 214 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 215 if (error) 216 goto bad; 217 } 218 if ((ap->a_mode & FWRITE) && fip->fi_readers == 0) { 219 VOP_UNLOCK(vp); 220 error = tsleep_nsec(&fip->fi_writers, 221 PCATCH | PSOCK, "fifow", INFSLP); 222 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 223 if (error) 224 goto bad; 225 } 226 } 227 return (0); 228 bad: 229 VOP_CLOSE(vp, ap->a_mode, ap->a_cred, ap->a_p); 230 return (error); 231 } 232 233 /* 234 * Vnode op for read 235 */ 236 /* ARGSUSED */ 237 int 238 fifo_read(void *v) 239 { 240 struct vop_read_args *ap = v; 241 struct uio *uio = ap->a_uio; 242 struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock; 243 int error, flags = 0; 244 245 #ifdef DIAGNOSTIC 246 if (uio->uio_rw != UIO_READ) 247 panic("fifo_read mode"); 248 #endif 249 if (uio->uio_resid == 0) 250 return (0); 251 if (ap->a_ioflag & IO_NDELAY) 252 flags |= MSG_DONTWAIT; 253 VOP_UNLOCK(ap->a_vp); 254 error = soreceive(rso, NULL, uio, NULL, NULL, &flags, 0); 255 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 256 if (ap->a_ioflag & IO_NDELAY) { 257 if (error == EWOULDBLOCK && 258 ap->a_vp->v_fifoinfo->fi_writers == 0) 259 error = 0; 260 } 261 return (error); 262 } 263 264 /* 265 * Vnode op for write 266 */ 267 /* ARGSUSED */ 268 int 269 fifo_write(void *v) 270 { 271 struct vop_write_args *ap = v; 272 struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock; 273 int error, flags = 0; 274 275 #ifdef DIAGNOSTIC 276 if (ap->a_uio->uio_rw != UIO_WRITE) 277 panic("fifo_write mode"); 278 #endif 279 if (ap->a_ioflag & IO_NDELAY) 280 flags |= MSG_DONTWAIT; 281 VOP_UNLOCK(ap->a_vp); 282 error = sosend(wso, NULL, ap->a_uio, NULL, NULL, flags); 283 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 284 return (error); 285 } 286 287 /* 288 * Device ioctl operation. 289 */ 290 /* ARGSUSED */ 291 int 292 fifo_ioctl(void *v) 293 { 294 struct vop_ioctl_args *ap = v; 295 struct file filetmp; 296 int error; 297 298 if (ap->a_command == FIONBIO) 299 return (0); 300 if (ap->a_fflag & FREAD) { 301 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_readsock; 302 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p); 303 if (error) 304 return (error); 305 } 306 if (ap->a_fflag & FWRITE) { 307 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_writesock; 308 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p); 309 if (error) 310 return (error); 311 } 312 return (0); 313 } 314 315 int 316 fifo_inactive(void *v) 317 { 318 struct vop_inactive_args *ap = v; 319 320 VOP_UNLOCK(ap->a_vp); 321 return (0); 322 } 323 324 325 /* 326 * Device close routine 327 */ 328 /* ARGSUSED */ 329 int 330 fifo_close(void *v) 331 { 332 struct vop_close_args *ap = v; 333 struct vnode *vp = ap->a_vp; 334 struct fifoinfo *fip = vp->v_fifoinfo; 335 int error1 = 0, error2 = 0; 336 337 if (fip == NULL) 338 return (0); 339 340 if (ap->a_fflag & FREAD) { 341 if (--fip->fi_readers == 0) { 342 struct socket *wso = fip->fi_writesock; 343 344 solock(wso); 345 socantsendmore(wso); 346 sounlock(wso); 347 } 348 } 349 if (ap->a_fflag & FWRITE) { 350 if (--fip->fi_writers == 0) { 351 struct socket *rso = fip->fi_readsock; 352 353 solock(rso); 354 /* SS_ISDISCONNECTED will result in POLLHUP */ 355 rso->so_state |= SS_ISDISCONNECTED; 356 socantrcvmore(rso); 357 sounlock(rso); 358 } 359 } 360 if (fip->fi_readers == 0 && fip->fi_writers == 0) { 361 error1 = soclose(fip->fi_readsock, 0); 362 error2 = soclose(fip->fi_writesock, 0); 363 free(fip, M_VNODE, sizeof *fip); 364 vp->v_fifoinfo = NULL; 365 } 366 return (error1 ? error1 : error2); 367 } 368 369 int 370 fifo_reclaim(void *v) 371 { 372 struct vop_reclaim_args *ap = v; 373 struct vnode *vp = ap->a_vp; 374 struct fifoinfo *fip = vp->v_fifoinfo; 375 376 if (fip == NULL) 377 return (0); 378 379 soclose(fip->fi_readsock, 0); 380 soclose(fip->fi_writesock, 0); 381 free(fip, M_VNODE, sizeof *fip); 382 vp->v_fifoinfo = NULL; 383 384 return (0); 385 } 386 387 /* 388 * Print out the contents of a fifo vnode. 389 */ 390 int 391 fifo_print(void *v) 392 { 393 struct vop_print_args *ap = v; 394 395 printf("tag VT_NON"); 396 fifo_printinfo(ap->a_vp); 397 printf("\n"); 398 return 0; 399 } 400 401 /* 402 * Print out internal contents of a fifo vnode. 403 */ 404 void 405 fifo_printinfo(struct vnode *vp) 406 { 407 struct fifoinfo *fip = vp->v_fifoinfo; 408 409 printf(", fifo with %ld readers and %ld writers", 410 fip->fi_readers, fip->fi_writers); 411 } 412 413 /* 414 * Return POSIX pathconf information applicable to fifo's. 415 */ 416 int 417 fifo_pathconf(void *v) 418 { 419 struct vop_pathconf_args *ap = v; 420 int error = 0; 421 422 switch (ap->a_name) { 423 case _PC_LINK_MAX: 424 *ap->a_retval = LINK_MAX; 425 break; 426 case _PC_CHOWN_RESTRICTED: 427 *ap->a_retval = 1; 428 break; 429 case _PC_TIMESTAMP_RESOLUTION: 430 *ap->a_retval = 1; 431 break; 432 default: 433 error = EINVAL; 434 break; 435 } 436 437 return (error); 438 } 439 440 /* 441 * Fifo failed operation 442 */ 443 /*ARGSUSED*/ 444 int 445 fifo_ebadf(void *v) 446 { 447 448 return (EBADF); 449 } 450 451 /* 452 * Fifo advisory byte-level locks. 453 */ 454 /* ARGSUSED */ 455 int 456 fifo_advlock(void *v) 457 { 458 return (EOPNOTSUPP); 459 } 460 461 int 462 fifo_kqfilter(void *v) 463 { 464 struct vop_kqfilter_args *ap = v; 465 struct fifoinfo *fip = ap->a_vp->v_fifoinfo; 466 struct sockbuf *sb; 467 struct socket *so; 468 469 switch (ap->a_kn->kn_filter) { 470 case EVFILT_READ: 471 if (!(ap->a_fflag & FREAD)) 472 return (EINVAL); 473 ap->a_kn->kn_fop = &fiforead_filtops; 474 so = fip->fi_readsock; 475 sb = &so->so_rcv; 476 break; 477 case EVFILT_WRITE: 478 if (!(ap->a_fflag & FWRITE)) { 479 /* Tell upper layer to ask for POLLUP only */ 480 if (ap->a_kn->kn_flags & (__EV_POLL | __EV_SELECT)) 481 return (EPERM); 482 return (EINVAL); 483 } 484 ap->a_kn->kn_fop = &fifowrite_filtops; 485 so = fip->fi_writesock; 486 sb = &so->so_snd; 487 break; 488 case EVFILT_EXCEPT: 489 if (ap->a_kn->kn_flags & __EV_SELECT) { 490 /* Prevent triggering exceptfds. */ 491 return (EPERM); 492 } 493 if ((ap->a_kn->kn_flags & __EV_POLL) == 0) { 494 /* Disallow usage through kevent(2). */ 495 return (EINVAL); 496 } 497 ap->a_kn->kn_fop = &fifoexcept_filtops; 498 so = fip->fi_readsock; 499 sb = &so->so_rcv; 500 break; 501 default: 502 return (EINVAL); 503 } 504 505 ap->a_kn->kn_hook = so; 506 507 klist_insert(&sb->sb_sel.si_note, ap->a_kn); 508 509 return (0); 510 } 511 512 void 513 filt_fifordetach(struct knote *kn) 514 { 515 struct socket *so = (struct socket *)kn->kn_hook; 516 517 klist_remove(&so->so_rcv.sb_sel.si_note, kn); 518 } 519 520 int 521 filt_fiforead(struct knote *kn, long hint) 522 { 523 struct socket *so = kn->kn_hook; 524 int rv; 525 526 soassertlocked(so); 527 528 kn->kn_data = so->so_rcv.sb_cc; 529 if (so->so_rcv.sb_state & SS_CANTRCVMORE) { 530 kn->kn_flags |= EV_EOF; 531 if (kn->kn_flags & __EV_POLL) { 532 if (so->so_state & SS_ISDISCONNECTED) 533 kn->kn_flags |= __EV_HUP; 534 else 535 kn->kn_flags &= ~__EV_HUP; 536 } 537 rv = 1; 538 } else { 539 kn->kn_flags &= ~(EV_EOF | __EV_HUP); 540 rv = (kn->kn_data > 0); 541 } 542 543 return (rv); 544 } 545 546 void 547 filt_fifowdetach(struct knote *kn) 548 { 549 struct socket *so = (struct socket *)kn->kn_hook; 550 551 klist_remove(&so->so_snd.sb_sel.si_note, kn); 552 } 553 554 int 555 filt_fifowrite(struct knote *kn, long hint) 556 { 557 struct socket *so = kn->kn_hook; 558 int rv; 559 560 soassertlocked(so); 561 562 kn->kn_data = sbspace(so, &so->so_snd); 563 if (so->so_snd.sb_state & SS_CANTSENDMORE) { 564 kn->kn_flags |= EV_EOF; 565 rv = 1; 566 } else { 567 kn->kn_flags &= ~EV_EOF; 568 rv = (kn->kn_data >= so->so_snd.sb_lowat); 569 } 570 571 return (rv); 572 } 573 574 int 575 filt_fifoexcept(struct knote *kn, long hint) 576 { 577 struct socket *so = kn->kn_hook; 578 int rv = 0; 579 580 soassertlocked(so); 581 582 if (kn->kn_flags & __EV_POLL) { 583 if (so->so_state & SS_ISDISCONNECTED) { 584 kn->kn_flags |= __EV_HUP; 585 rv = 1; 586 } else { 587 kn->kn_flags &= ~__EV_HUP; 588 } 589 } 590 591 return (rv); 592 } 593 594 int 595 filt_fifomodify(struct kevent *kev, struct knote *kn) 596 { 597 struct socket *so = kn->kn_hook; 598 int rv; 599 600 solock(so); 601 rv = knote_modify(kev, kn); 602 sounlock(so); 603 604 return (rv); 605 } 606 607 int 608 filt_fifoprocess(struct knote *kn, struct kevent *kev) 609 { 610 struct socket *so = kn->kn_hook; 611 int rv; 612 613 solock(so); 614 rv = knote_process(kn, kev); 615 sounlock(so); 616 617 return (rv); 618 } 619