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