1 /* $NetBSD: fifo_vnops.c,v 1.75 2014/05/17 23:30:24 rmind 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.75 2014/05/17 23:30:24 rmind 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 /* 99 * Trivial lookup routine that always fails. 100 */ 101 /* ARGSUSED */ 102 static int 103 fifo_lookup(void *v) 104 { 105 struct vop_lookup_v2_args /* { 106 struct vnode *a_dvp; 107 struct vnode **a_vpp; 108 struct componentname *a_cnp; 109 } */ *ap = v; 110 111 *ap->a_vpp = NULL; 112 return (ENOTDIR); 113 } 114 115 /* 116 * Open called to set up a new instance of a fifo or 117 * to find an active instance of a fifo. 118 */ 119 static int 120 fifo_open(void *v) 121 { 122 struct vop_open_args /* { 123 struct vnode *a_vp; 124 int a_mode; 125 kauth_cred_t a_cred; 126 } */ *ap = v; 127 struct lwp *l = curlwp; 128 struct vnode *vp; 129 struct fifoinfo *fip; 130 struct socket *rso, *wso; 131 int error; 132 133 vp = ap->a_vp; 134 KASSERT(VOP_ISLOCKED(vp)); 135 136 if ((fip = vp->v_fifoinfo) == NULL) { 137 fip = kmem_alloc(sizeof(*fip), KM_SLEEP); 138 error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0, l, NULL); 139 if (error != 0) { 140 kmem_free(fip, sizeof(*fip)); 141 return (error); 142 } 143 fip->fi_readsock = rso; 144 error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0, l, rso); 145 if (error != 0) { 146 (void)soclose(rso); 147 kmem_free(fip, sizeof(*fip)); 148 return (error); 149 } 150 fip->fi_writesock = wso; 151 solock(wso); 152 if ((error = unp_connect2(wso, rso, PRU_CONNECT2)) != 0) { 153 sounlock(wso); 154 (void)soclose(wso); 155 (void)soclose(rso); 156 kmem_free(fip, sizeof(*fip)); 157 return (error); 158 } 159 fip->fi_readers = 0; 160 fip->fi_writers = 0; 161 wso->so_state |= SS_CANTRCVMORE; 162 rso->so_state |= SS_CANTSENDMORE; 163 cv_init(&fip->fi_rcv, "fiford"); 164 cv_init(&fip->fi_wcv, "fifowr"); 165 vp->v_fifoinfo = fip; 166 } else { 167 wso = fip->fi_writesock; 168 rso = fip->fi_readsock; 169 solock(wso); 170 } 171 172 if (ap->a_mode & FREAD) { 173 if (fip->fi_readers++ == 0) { 174 wso->so_state &= ~SS_CANTSENDMORE; 175 cv_broadcast(&fip->fi_wcv); 176 } 177 } 178 if (ap->a_mode & FWRITE) { 179 if (fip->fi_writers++ == 0) { 180 rso->so_state &= ~SS_CANTRCVMORE; 181 cv_broadcast(&fip->fi_rcv); 182 } 183 } 184 if (ap->a_mode & FREAD) { 185 if (ap->a_mode & O_NONBLOCK) { 186 } else { 187 while (!soreadable(rso) && fip->fi_writers == 0) { 188 VOP_UNLOCK(vp); 189 error = cv_wait_sig(&fip->fi_rcv, 190 wso->so_lock); 191 sounlock(wso); 192 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 193 if (error) 194 goto bad; 195 solock(wso); 196 } 197 } 198 } 199 if (ap->a_mode & FWRITE) { 200 if (ap->a_mode & O_NONBLOCK) { 201 if (fip->fi_readers == 0) { 202 error = ENXIO; 203 sounlock(wso); 204 goto bad; 205 } 206 } else { 207 while (fip->fi_readers == 0) { 208 VOP_UNLOCK(vp); 209 error = cv_wait_sig(&fip->fi_wcv, 210 wso->so_lock); 211 sounlock(wso); 212 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 213 if (error) 214 goto bad; 215 solock(wso); 216 } 217 } 218 } 219 sounlock(wso); 220 return (0); 221 bad: 222 VOP_CLOSE(vp, ap->a_mode, ap->a_cred); 223 return (error); 224 } 225 226 /* 227 * Vnode op for read 228 */ 229 /* ARGSUSED */ 230 static int 231 fifo_read(void *v) 232 { 233 struct vop_read_args /* { 234 struct vnode *a_vp; 235 struct uio *a_uio; 236 int a_ioflag; 237 kauth_cred_t a_cred; 238 } */ *ap = v; 239 struct uio *uio; 240 struct socket *rso; 241 int error, sflags; 242 size_t startresid; 243 244 uio = ap->a_uio; 245 rso = ap->a_vp->v_fifoinfo->fi_readsock; 246 #ifdef DIAGNOSTIC 247 if (uio->uio_rw != UIO_READ) 248 panic("fifo_read mode"); 249 #endif 250 if (uio->uio_resid == 0) 251 return (0); 252 startresid = uio->uio_resid; 253 VOP_UNLOCK(ap->a_vp); 254 sflags = (ap->a_ioflag & IO_NDELAY) ? MSG_NBIO : 0; 255 error = (*rso->so_receive)(rso, NULL, uio, NULL, NULL, &sflags); 256 /* 257 * Clear EOF indication after first such return. 258 */ 259 if (error == 0 && uio->uio_resid == startresid) 260 rso->so_state &= ~SS_CANTRCVMORE; 261 if (ap->a_ioflag & IO_NDELAY) { 262 if (error == EWOULDBLOCK && 263 ap->a_vp->v_fifoinfo->fi_writers == 0) 264 error = 0; 265 } 266 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 267 return (error); 268 } 269 270 /* 271 * Vnode op for write 272 */ 273 /* ARGSUSED */ 274 static int 275 fifo_write(void *v) 276 { 277 struct vop_write_args /* { 278 struct vnode *a_vp; 279 struct uio *a_uio; 280 int a_ioflag; 281 kauth_cred_t a_cred; 282 } */ *ap = v; 283 struct socket *wso; 284 int error, sflags; 285 286 wso = ap->a_vp->v_fifoinfo->fi_writesock; 287 #ifdef DIAGNOSTIC 288 if (ap->a_uio->uio_rw != UIO_WRITE) 289 panic("fifo_write mode"); 290 #endif 291 VOP_UNLOCK(ap->a_vp); 292 sflags = (ap->a_ioflag & IO_NDELAY) ? MSG_NBIO : 0; 293 error = (*wso->so_send)(wso, NULL, ap->a_uio, 0, NULL, sflags, curlwp); 294 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 295 return (error); 296 } 297 298 /* 299 * Device ioctl operation. 300 */ 301 /* ARGSUSED */ 302 static int 303 fifo_ioctl(void *v) 304 { 305 struct vop_ioctl_args /* { 306 struct vnode *a_vp; 307 u_long a_command; 308 void *a_data; 309 int a_fflag; 310 kauth_cred_t a_cred; 311 struct lwp *a_l; 312 } */ *ap = v; 313 struct file filetmp; 314 int error; 315 316 if (ap->a_command == FIONBIO) 317 return (0); 318 if (ap->a_fflag & FREAD) { 319 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_readsock; 320 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data); 321 if (error) 322 return (error); 323 } 324 if (ap->a_fflag & FWRITE) { 325 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_writesock; 326 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data); 327 if (error) 328 return (error); 329 } 330 return (0); 331 } 332 333 /* ARGSUSED */ 334 static int 335 fifo_poll(void *v) 336 { 337 struct vop_poll_args /* { 338 struct vnode *a_vp; 339 int a_events; 340 struct lwp *a_l; 341 } */ *ap = v; 342 struct socket *so; 343 int revents; 344 345 revents = 0; 346 if (ap->a_events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) { 347 so = ap->a_vp->v_fifoinfo->fi_readsock; 348 if (so) 349 revents |= sopoll(so, ap->a_events); 350 } 351 if (ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND)) { 352 so = ap->a_vp->v_fifoinfo->fi_writesock; 353 if (so) 354 revents |= sopoll(so, ap->a_events); 355 } 356 357 return (revents); 358 } 359 360 static int 361 fifo_inactive(void *v) 362 { 363 struct vop_inactive_args /* { 364 struct vnode *a_vp; 365 struct lwp *a_l; 366 } */ *ap = v; 367 368 VOP_UNLOCK(ap->a_vp); 369 return (0); 370 } 371 372 /* 373 * This is a noop, simply returning what one has been given. 374 */ 375 static int 376 fifo_bmap(void *v) 377 { 378 struct vop_bmap_args /* { 379 struct vnode *a_vp; 380 daddr_t a_bn; 381 struct vnode **a_vpp; 382 daddr_t *a_bnp; 383 int *a_runp; 384 } */ *ap = v; 385 386 if (ap->a_vpp != NULL) 387 *ap->a_vpp = ap->a_vp; 388 if (ap->a_bnp != NULL) 389 *ap->a_bnp = ap->a_bn; 390 if (ap->a_runp != NULL) 391 *ap->a_runp = 0; 392 return (0); 393 } 394 395 /* 396 * Device close routine 397 */ 398 /* ARGSUSED */ 399 static int 400 fifo_close(void *v) 401 { 402 struct vop_close_args /* { 403 struct vnode *a_vp; 404 int a_fflag; 405 kauth_cred_t a_cred; 406 struct lwp *a_l; 407 } */ *ap = v; 408 struct vnode *vp; 409 struct fifoinfo *fip; 410 struct socket *wso, *rso; 411 int isrevoke; 412 413 vp = ap->a_vp; 414 fip = vp->v_fifoinfo; 415 isrevoke = (ap->a_fflag & (FREAD | FWRITE | FNONBLOCK)) == FNONBLOCK; 416 wso = fip->fi_writesock; 417 rso = fip->fi_readsock; 418 solock(wso); 419 if (isrevoke) { 420 if (fip->fi_readers != 0) { 421 fip->fi_readers = 0; 422 socantsendmore(wso); 423 } 424 if (fip->fi_writers != 0) { 425 fip->fi_writers = 0; 426 socantrcvmore(rso); 427 } 428 } else { 429 if ((ap->a_fflag & FREAD) && --fip->fi_readers == 0) 430 socantsendmore(wso); 431 if ((ap->a_fflag & FWRITE) && --fip->fi_writers == 0) 432 socantrcvmore(rso); 433 } 434 if ((fip->fi_readers + fip->fi_writers) == 0) { 435 sounlock(wso); 436 (void) soclose(rso); 437 (void) soclose(wso); 438 cv_destroy(&fip->fi_rcv); 439 cv_destroy(&fip->fi_wcv); 440 kmem_free(fip, sizeof(*fip)); 441 vp->v_fifoinfo = NULL; 442 } else 443 sounlock(wso); 444 return (0); 445 } 446 447 /* 448 * Print out internal contents of a fifo vnode. 449 */ 450 static void 451 fifo_printinfo(struct vnode *vp) 452 { 453 struct fifoinfo *fip; 454 455 fip = vp->v_fifoinfo; 456 printf(", fifo with %d readers and %d writers", 457 fip->fi_readers, fip->fi_writers); 458 } 459 460 /* 461 * Print out the contents of a fifo vnode. 462 */ 463 static int 464 fifo_print(void *v) 465 { 466 struct vop_print_args /* { 467 struct vnode *a_vp; 468 } */ *ap = v; 469 470 /* 471 * We are most likely being called with the vnode belonging 472 * to some file system and this is not printed. 473 */ 474 if (ap->a_vp->v_tag == VT_NON) 475 printf("tag VT_NON"); 476 477 fifo_printinfo(ap->a_vp); 478 printf("\n"); 479 return 0; 480 } 481 482 /* 483 * Return POSIX pathconf information applicable to fifo's. 484 */ 485 static int 486 fifo_pathconf(void *v) 487 { 488 struct vop_pathconf_args /* { 489 struct vnode *a_vp; 490 int a_name; 491 register_t *a_retval; 492 } */ *ap = v; 493 494 switch (ap->a_name) { 495 case _PC_LINK_MAX: 496 *ap->a_retval = LINK_MAX; 497 return (0); 498 case _PC_PIPE_BUF: 499 *ap->a_retval = PIPE_BUF; 500 return (0); 501 case _PC_CHOWN_RESTRICTED: 502 *ap->a_retval = 1; 503 return (0); 504 case _PC_SYNC_IO: 505 *ap->a_retval = 1; 506 return (0); 507 default: 508 return (EINVAL); 509 } 510 /* NOTREACHED */ 511 } 512 513 static void 514 filt_fifordetach(struct knote *kn) 515 { 516 struct socket *so; 517 518 so = (struct socket *)kn->kn_hook; 519 solock(so); 520 SLIST_REMOVE(&so->so_rcv.sb_sel.sel_klist, kn, knote, kn_selnext); 521 if (SLIST_EMPTY(&so->so_rcv.sb_sel.sel_klist)) 522 so->so_rcv.sb_flags &= ~SB_KNOTE; 523 sounlock(so); 524 } 525 526 static int 527 filt_fiforead(struct knote *kn, long hint) 528 { 529 struct socket *so; 530 int rv; 531 532 so = (struct socket *)kn->kn_hook; 533 if (hint != NOTE_SUBMIT) 534 solock(so); 535 kn->kn_data = so->so_rcv.sb_cc; 536 if (so->so_state & SS_CANTRCVMORE) { 537 kn->kn_flags |= EV_EOF; 538 rv = 1; 539 } else { 540 kn->kn_flags &= ~EV_EOF; 541 rv = (kn->kn_data > 0); 542 } 543 if (hint != NOTE_SUBMIT) 544 sounlock(so); 545 return rv; 546 } 547 548 static void 549 filt_fifowdetach(struct knote *kn) 550 { 551 struct socket *so; 552 553 so = (struct socket *)kn->kn_hook; 554 solock(so); 555 SLIST_REMOVE(&so->so_snd.sb_sel.sel_klist, kn, knote, kn_selnext); 556 if (SLIST_EMPTY(&so->so_snd.sb_sel.sel_klist)) 557 so->so_snd.sb_flags &= ~SB_KNOTE; 558 sounlock(so); 559 } 560 561 static int 562 filt_fifowrite(struct knote *kn, long hint) 563 { 564 struct socket *so; 565 int rv; 566 567 so = (struct socket *)kn->kn_hook; 568 if (hint != NOTE_SUBMIT) 569 solock(so); 570 kn->kn_data = sbspace(&so->so_snd); 571 if (so->so_state & SS_CANTSENDMORE) { 572 kn->kn_flags |= EV_EOF; 573 rv = 1; 574 } else { 575 kn->kn_flags &= ~EV_EOF; 576 rv = (kn->kn_data >= so->so_snd.sb_lowat); 577 } 578 if (hint != NOTE_SUBMIT) 579 sounlock(so); 580 return rv; 581 } 582 583 static const struct filterops fiforead_filtops = 584 { 1, NULL, filt_fifordetach, filt_fiforead }; 585 static const struct filterops fifowrite_filtops = 586 { 1, NULL, filt_fifowdetach, filt_fifowrite }; 587 588 /* ARGSUSED */ 589 static int 590 fifo_kqfilter(void *v) 591 { 592 struct vop_kqfilter_args /* { 593 struct vnode *a_vp; 594 struct knote *a_kn; 595 } */ *ap = v; 596 struct socket *so; 597 struct sockbuf *sb; 598 599 so = (struct socket *)ap->a_vp->v_fifoinfo->fi_readsock; 600 switch (ap->a_kn->kn_filter) { 601 case EVFILT_READ: 602 ap->a_kn->kn_fop = &fiforead_filtops; 603 sb = &so->so_rcv; 604 break; 605 case EVFILT_WRITE: 606 ap->a_kn->kn_fop = &fifowrite_filtops; 607 sb = &so->so_snd; 608 break; 609 default: 610 return (EINVAL); 611 } 612 613 ap->a_kn->kn_hook = so; 614 615 solock(so); 616 SLIST_INSERT_HEAD(&sb->sb_sel.sel_klist, ap->a_kn, kn_selnext); 617 sb->sb_flags |= SB_KNOTE; 618 sounlock(so); 619 620 return (0); 621 } 622 623 int (**fifo_vnodeop_p)(void *); 624 const struct vnodeopv_entry_desc fifo_vnodeop_entries[] = { 625 { &vop_default_desc, vn_default_error }, 626 { &vop_lookup_desc, fifo_lookup }, /* lookup */ 627 { &vop_create_desc, genfs_badop }, /* create */ 628 { &vop_mknod_desc, genfs_badop }, /* mknod */ 629 { &vop_open_desc, fifo_open }, /* open */ 630 { &vop_close_desc, fifo_close }, /* close */ 631 { &vop_access_desc, genfs_ebadf }, /* access */ 632 { &vop_getattr_desc, genfs_ebadf }, /* getattr */ 633 { &vop_setattr_desc, genfs_ebadf }, /* setattr */ 634 { &vop_read_desc, fifo_read }, /* read */ 635 { &vop_write_desc, fifo_write }, /* write */ 636 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 637 { &vop_poll_desc, fifo_poll }, /* poll */ 638 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */ 639 { &vop_revoke_desc, genfs_revoke }, /* revoke */ 640 { &vop_mmap_desc, genfs_badop }, /* mmap */ 641 { &vop_fsync_desc, genfs_nullop }, /* fsync */ 642 { &vop_seek_desc, genfs_badop }, /* seek */ 643 { &vop_remove_desc, genfs_badop }, /* remove */ 644 { &vop_link_desc, genfs_badop }, /* link */ 645 { &vop_rename_desc, genfs_badop }, /* rename */ 646 { &vop_mkdir_desc, genfs_badop }, /* mkdir */ 647 { &vop_rmdir_desc, genfs_badop }, /* rmdir */ 648 { &vop_symlink_desc, genfs_badop }, /* symlink */ 649 { &vop_readdir_desc, genfs_badop }, /* readdir */ 650 { &vop_readlink_desc, genfs_badop }, /* readlink */ 651 { &vop_abortop_desc, genfs_badop }, /* abortop */ 652 { &vop_inactive_desc, fifo_inactive }, /* inactive */ 653 { &vop_reclaim_desc, genfs_nullop }, /* reclaim */ 654 { &vop_lock_desc, genfs_lock }, /* lock */ 655 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 656 { &vop_bmap_desc, fifo_bmap }, /* bmap */ 657 { &vop_strategy_desc, genfs_badop }, /* strategy */ 658 { &vop_print_desc, fifo_print }, /* print */ 659 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 660 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 661 { &vop_advlock_desc, genfs_einval }, /* advlock */ 662 { &vop_bwrite_desc, genfs_nullop }, /* bwrite */ 663 { &vop_putpages_desc, genfs_null_putpages }, /* putpages */ 664 { NULL, NULL } 665 }; 666 const struct vnodeopv_desc fifo_vnodeop_opv_desc = 667 { &fifo_vnodeop_p, fifo_vnodeop_entries }; 668