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