fifo_vnops.c revision 1.69 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