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