fifo_vnops.c revision 1.65 1 /* $NetBSD: fifo_vnops.c,v 1.65 2008/04/24 15:18:11 ad 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 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the NetBSD
18 * Foundation, Inc. and its contributors.
19 * 4. Neither the name of The NetBSD Foundation nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 /*
37 * Copyright (c) 1990, 1993, 1995
38 * The Regents of the University of California. All rights reserved.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 * @(#)fifo_vnops.c 8.10 (Berkeley) 5/27/95
65 */
66
67 #include <sys/cdefs.h>
68 __KERNEL_RCSID(0, "$NetBSD: fifo_vnops.c,v 1.65 2008/04/24 15:18:11 ad Exp $");
69
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/proc.h>
73 #include <sys/time.h>
74 #include <sys/namei.h>
75 #include <sys/vnode.h>
76 #include <sys/socket.h>
77 #include <sys/protosw.h>
78 #include <sys/socketvar.h>
79 #include <sys/stat.h>
80 #include <sys/ioctl.h>
81 #include <sys/file.h>
82 #include <sys/errno.h>
83 #include <sys/kmem.h>
84 #include <sys/un.h>
85 #include <sys/poll.h>
86 #include <sys/event.h>
87 #include <sys/condvar.h>
88
89 #include <miscfs/fifofs/fifo.h>
90 #include <miscfs/genfs/genfs.h>
91
92 /*
93 * This structure is associated with the FIFO vnode and stores
94 * the state associated with the FIFO.
95 */
96 struct fifoinfo {
97 struct socket *fi_readsock;
98 struct socket *fi_writesock;
99 kcondvar_t fi_rcv;
100 int fi_readers;
101 kcondvar_t fi_wcv;
102 int fi_writers;
103 };
104
105 int (**fifo_vnodeop_p)(void *);
106 const struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
107 { &vop_default_desc, vn_default_error },
108 { &vop_lookup_desc, fifo_lookup }, /* lookup */
109 { &vop_create_desc, fifo_create }, /* create */
110 { &vop_mknod_desc, fifo_mknod }, /* mknod */
111 { &vop_open_desc, fifo_open }, /* open */
112 { &vop_close_desc, fifo_close }, /* close */
113 { &vop_access_desc, fifo_access }, /* access */
114 { &vop_getattr_desc, fifo_getattr }, /* getattr */
115 { &vop_setattr_desc, fifo_setattr }, /* setattr */
116 { &vop_read_desc, fifo_read }, /* read */
117 { &vop_write_desc, fifo_write }, /* write */
118 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
119 { &vop_poll_desc, fifo_poll }, /* poll */
120 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */
121 { &vop_revoke_desc, fifo_revoke }, /* revoke */
122 { &vop_mmap_desc, fifo_mmap }, /* mmap */
123 { &vop_fsync_desc, fifo_fsync }, /* fsync */
124 { &vop_seek_desc, fifo_seek }, /* seek */
125 { &vop_remove_desc, fifo_remove }, /* remove */
126 { &vop_link_desc, fifo_link }, /* link */
127 { &vop_rename_desc, fifo_rename }, /* rename */
128 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
129 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
130 { &vop_symlink_desc, fifo_symlink }, /* symlink */
131 { &vop_readdir_desc, fifo_readdir }, /* readdir */
132 { &vop_readlink_desc, fifo_readlink }, /* readlink */
133 { &vop_abortop_desc, fifo_abortop }, /* abortop */
134 { &vop_inactive_desc, fifo_inactive }, /* inactive */
135 { &vop_reclaim_desc, fifo_reclaim }, /* reclaim */
136 { &vop_lock_desc, fifo_lock }, /* lock */
137 { &vop_unlock_desc, fifo_unlock }, /* unlock */
138 { &vop_bmap_desc, fifo_bmap }, /* bmap */
139 { &vop_strategy_desc, fifo_strategy }, /* strategy */
140 { &vop_print_desc, fifo_print }, /* print */
141 { &vop_islocked_desc, fifo_islocked }, /* islocked */
142 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
143 { &vop_advlock_desc, fifo_advlock }, /* advlock */
144 { &vop_bwrite_desc, fifo_bwrite }, /* bwrite */
145 { &vop_putpages_desc, fifo_putpages }, /* putpages */
146 { (struct vnodeop_desc*)NULL, (int(*)(void *))NULL }
147 };
148 const struct vnodeopv_desc fifo_vnodeop_opv_desc =
149 { &fifo_vnodeop_p, fifo_vnodeop_entries };
150
151 /*
152 * Trivial lookup routine that always fails.
153 */
154 /* ARGSUSED */
155 int
156 fifo_lookup(void *v)
157 {
158 struct vop_lookup_args /* {
159 struct vnode *a_dvp;
160 struct vnode **a_vpp;
161 struct componentname *a_cnp;
162 } */ *ap = v;
163
164 *ap->a_vpp = NULL;
165 return (ENOTDIR);
166 }
167
168 /*
169 * Open called to set up a new instance of a fifo or
170 * to find an active instance of a fifo.
171 */
172 /* ARGSUSED */
173 int
174 fifo_open(void *v)
175 {
176 struct vop_open_args /* {
177 struct vnode *a_vp;
178 int a_mode;
179 kauth_cred_t a_cred;
180 } */ *ap = v;
181 struct lwp *l = curlwp;
182 struct vnode *vp;
183 struct fifoinfo *fip;
184 struct proc *p;
185 struct socket *rso, *wso;
186 int error;
187
188 vp = ap->a_vp;
189 p = l->l_proc;
190
191 if ((fip = vp->v_fifoinfo) == NULL) {
192 fip = kmem_alloc(sizeof(*fip), KM_SLEEP);
193 vp->v_fifoinfo = fip;
194 error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0, l, NULL);
195 if (error != 0) {
196 kmem_free(fip, sizeof(*fip));
197 vp->v_fifoinfo = NULL;
198 return (error);
199 }
200 fip->fi_readsock = rso;
201 error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0, l, rso);
202 if (error != 0) {
203 (void)soclose(rso);
204 kmem_free(fip, sizeof(*fip));
205 vp->v_fifoinfo = NULL;
206 return (error);
207 }
208 fip->fi_writesock = wso;
209 solock(wso);
210 if ((error = unp_connect2(wso, rso, PRU_CONNECT2)) != 0) {
211 sounlock(wso);
212 (void)soclose(wso);
213 (void)soclose(rso);
214 kmem_free(fip, sizeof(*fip));
215 vp->v_fifoinfo = NULL;
216 return (error);
217 }
218 fip->fi_readers = 0;
219 fip->fi_writers = 0;
220 wso->so_state |= SS_CANTRCVMORE;
221 rso->so_state |= SS_CANTSENDMORE;
222 cv_init(&fip->fi_rcv, "fiford");
223 cv_init(&fip->fi_wcv, "fifowr");
224 } else {
225 wso = fip->fi_writesock;
226 rso = fip->fi_readsock;
227 solock(wso);
228 }
229
230 if (ap->a_mode & FREAD) {
231 if (fip->fi_readers++ == 0) {
232 wso->so_state &= ~SS_CANTSENDMORE;
233 cv_broadcast(&fip->fi_wcv);
234 }
235 }
236 if (ap->a_mode & FWRITE) {
237 if (fip->fi_writers++ == 0) {
238 rso->so_state &= ~SS_CANTRCVMORE;
239 cv_broadcast(&fip->fi_rcv);
240 }
241 }
242 if (ap->a_mode & FREAD) {
243 if (ap->a_mode & O_NONBLOCK) {
244 } else {
245 while (!soreadable(rso) && fip->fi_writers == 0) {
246 VOP_UNLOCK(vp, 0);
247 error = cv_wait_sig(&fip->fi_rcv,
248 wso->so_lock);
249 sounlock(wso);
250 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
251 if (error)
252 goto bad;
253 solock(wso);
254 }
255 }
256 }
257 if (ap->a_mode & FWRITE) {
258 if (ap->a_mode & O_NONBLOCK) {
259 if (fip->fi_readers == 0) {
260 error = ENXIO;
261 sounlock(wso);
262 goto bad;
263 }
264 } else {
265 while (fip->fi_readers == 0) {
266 VOP_UNLOCK(vp, 0);
267 error = cv_wait_sig(&fip->fi_wcv,
268 wso->so_lock);
269 sounlock(wso);
270 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
271 if (error)
272 goto bad;
273 solock(wso);
274 }
275 }
276 }
277 sounlock(wso);
278 return (0);
279 bad:
280 VOP_CLOSE(vp, ap->a_mode, ap->a_cred);
281 return (error);
282 }
283
284 /*
285 * Vnode op for read
286 */
287 /* ARGSUSED */
288 int
289 fifo_read(void *v)
290 {
291 struct vop_read_args /* {
292 struct vnode *a_vp;
293 struct uio *a_uio;
294 int a_ioflag;
295 kauth_cred_t a_cred;
296 } */ *ap = v;
297 struct uio *uio;
298 struct socket *rso;
299 int error;
300 size_t startresid;
301
302 uio = ap->a_uio;
303 rso = ap->a_vp->v_fifoinfo->fi_readsock;
304 #ifdef DIAGNOSTIC
305 if (uio->uio_rw != UIO_READ)
306 panic("fifo_read mode");
307 #endif
308 if (uio->uio_resid == 0)
309 return (0);
310 startresid = uio->uio_resid;
311 VOP_UNLOCK(ap->a_vp, 0);
312 if (ap->a_ioflag & IO_NDELAY) {
313 /* XXX Bogus, affects other threads. */
314 rso->so_nbio = 1;
315 }
316 error = (*rso->so_receive)(rso, NULL, uio, NULL, NULL, NULL);
317 /*
318 * Clear EOF indication after first such return.
319 */
320 if (uio->uio_resid == startresid)
321 rso->so_state &= ~SS_CANTRCVMORE;
322 if (ap->a_ioflag & IO_NDELAY) {
323 rso->so_nbio = 0;
324 if (error == EWOULDBLOCK &&
325 ap->a_vp->v_fifoinfo->fi_writers == 0)
326 error = 0;
327 }
328 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
329 return (error);
330 }
331
332 /*
333 * Vnode op for write
334 */
335 /* ARGSUSED */
336 int
337 fifo_write(void *v)
338 {
339 struct vop_write_args /* {
340 struct vnode *a_vp;
341 struct uio *a_uio;
342 int a_ioflag;
343 kauth_cred_t a_cred;
344 } */ *ap = v;
345 struct socket *wso;
346 int error;
347
348 wso = ap->a_vp->v_fifoinfo->fi_writesock;
349 #ifdef DIAGNOSTIC
350 if (ap->a_uio->uio_rw != UIO_WRITE)
351 panic("fifo_write mode");
352 #endif
353 VOP_UNLOCK(ap->a_vp, 0);
354 if (ap->a_ioflag & IO_NDELAY) {
355 /* XXX Bogus, affects other threads. */
356 wso->so_nbio = 1;
357 }
358 error = (*wso->so_send)(wso, NULL, ap->a_uio, 0, NULL, 0, curlwp);
359 if (ap->a_ioflag & IO_NDELAY)
360 wso->so_nbio = 0;
361 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
362 return (error);
363 }
364
365 /*
366 * Device ioctl operation.
367 */
368 /* ARGSUSED */
369 int
370 fifo_ioctl(void *v)
371 {
372 struct vop_ioctl_args /* {
373 struct vnode *a_vp;
374 u_long a_command;
375 void *a_data;
376 int a_fflag;
377 kauth_cred_t a_cred;
378 struct lwp *a_l;
379 } */ *ap = v;
380 struct file filetmp;
381 int error;
382
383 if (ap->a_command == FIONBIO)
384 return (0);
385 if (ap->a_fflag & FREAD) {
386 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_readsock;
387 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data);
388 if (error)
389 return (error);
390 }
391 if (ap->a_fflag & FWRITE) {
392 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_writesock;
393 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data);
394 if (error)
395 return (error);
396 }
397 return (0);
398 }
399
400 /* ARGSUSED */
401 int
402 fifo_poll(void *v)
403 {
404 struct vop_poll_args /* {
405 struct vnode *a_vp;
406 int a_events;
407 struct lwp *a_l;
408 } */ *ap = v;
409 struct socket *so;
410 int revents;
411
412 revents = 0;
413 if (ap->a_events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
414 so = ap->a_vp->v_fifoinfo->fi_readsock;
415 if (so)
416 revents |= sopoll(so, ap->a_events);
417 }
418 if (ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
419 so = ap->a_vp->v_fifoinfo->fi_writesock;
420 if (so)
421 revents |= sopoll(so, ap->a_events);
422 }
423
424 return (revents);
425 }
426
427 int
428 fifo_inactive(void *v)
429 {
430 struct vop_inactive_args /* {
431 struct vnode *a_vp;
432 struct lwp *a_l;
433 } */ *ap = v;
434
435 VOP_UNLOCK(ap->a_vp, 0);
436 return (0);
437 }
438
439 /*
440 * This is a noop, simply returning what one has been given.
441 */
442 int
443 fifo_bmap(void *v)
444 {
445 struct vop_bmap_args /* {
446 struct vnode *a_vp;
447 daddr_t a_bn;
448 struct vnode **a_vpp;
449 daddr_t *a_bnp;
450 int *a_runp;
451 } */ *ap = v;
452
453 if (ap->a_vpp != NULL)
454 *ap->a_vpp = ap->a_vp;
455 if (ap->a_bnp != NULL)
456 *ap->a_bnp = ap->a_bn;
457 if (ap->a_runp != NULL)
458 *ap->a_runp = 0;
459 return (0);
460 }
461
462 /*
463 * Device close routine
464 */
465 /* ARGSUSED */
466 int
467 fifo_close(void *v)
468 {
469 struct vop_close_args /* {
470 struct vnode *a_vp;
471 int a_fflag;
472 kauth_cred_t a_cred;
473 struct lwp *a_l;
474 } */ *ap = v;
475 struct vnode *vp;
476 struct fifoinfo *fip;
477 struct socket *wso, *rso;
478 int isrevoke;
479
480 vp = ap->a_vp;
481 fip = vp->v_fifoinfo;
482 isrevoke = (ap->a_fflag & (FREAD | FWRITE | FNONBLOCK)) == FNONBLOCK;
483 wso = fip->fi_writesock;
484 rso = fip->fi_readsock;
485 solock(wso);
486 if (isrevoke) {
487 if (fip->fi_readers != 0) {
488 fip->fi_readers = 0;
489 socantsendmore(wso);
490 }
491 if (fip->fi_writers != 0) {
492 fip->fi_writers = 0;
493 socantrcvmore(rso);
494 }
495 } else {
496 if ((ap->a_fflag & FREAD) && --fip->fi_readers == 0)
497 socantsendmore(wso);
498 if ((ap->a_fflag & FWRITE) && --fip->fi_writers == 0)
499 socantrcvmore(rso);
500 }
501 if ((fip->fi_readers + fip->fi_writers) == 0) {
502 sounlock(wso);
503 (void) soclose(rso);
504 (void) soclose(wso);
505 cv_destroy(&fip->fi_rcv);
506 cv_destroy(&fip->fi_wcv);
507 kmem_free(fip, sizeof(*fip));
508 vp->v_fifoinfo = NULL;
509 } else
510 sounlock(wso);
511 return (0);
512 }
513
514 /*
515 * Print out the contents of a fifo vnode.
516 */
517 int
518 fifo_print(void *v)
519 {
520 struct vop_print_args /* {
521 struct vnode *a_vp;
522 } */ *ap = v;
523
524 printf("tag VT_NON");
525 fifo_printinfo(ap->a_vp);
526 printf("\n");
527 return 0;
528 }
529
530 /*
531 * Print out internal contents of a fifo vnode.
532 */
533 void
534 fifo_printinfo(struct vnode *vp)
535 {
536 struct fifoinfo *fip;
537
538 fip = vp->v_fifoinfo;
539 printf(", fifo with %d readers and %d writers",
540 fip->fi_readers, fip->fi_writers);
541 }
542
543 /*
544 * Return POSIX pathconf information applicable to fifo's.
545 */
546 int
547 fifo_pathconf(void *v)
548 {
549 struct vop_pathconf_args /* {
550 struct vnode *a_vp;
551 int a_name;
552 register_t *a_retval;
553 } */ *ap = v;
554
555 switch (ap->a_name) {
556 case _PC_LINK_MAX:
557 *ap->a_retval = LINK_MAX;
558 return (0);
559 case _PC_PIPE_BUF:
560 *ap->a_retval = PIPE_BUF;
561 return (0);
562 case _PC_CHOWN_RESTRICTED:
563 *ap->a_retval = 1;
564 return (0);
565 case _PC_SYNC_IO:
566 *ap->a_retval = 1;
567 return (0);
568 default:
569 return (EINVAL);
570 }
571 /* NOTREACHED */
572 }
573
574 static void
575 filt_fifordetach(struct knote *kn)
576 {
577 struct socket *so;
578
579 so = (struct socket *)kn->kn_hook;
580 solock(so);
581 SLIST_REMOVE(&so->so_rcv.sb_sel.sel_klist, kn, knote, kn_selnext);
582 if (SLIST_EMPTY(&so->so_rcv.sb_sel.sel_klist))
583 so->so_rcv.sb_flags &= ~SB_KNOTE;
584 sounlock(so);
585 }
586
587 static int
588 filt_fiforead(struct knote *kn, long hint)
589 {
590 struct socket *so;
591 int rv;
592
593 so = (struct socket *)kn->kn_hook;
594 if (hint != NOTE_SUBMIT)
595 solock(so);
596 kn->kn_data = so->so_rcv.sb_cc;
597 if (so->so_state & SS_CANTRCVMORE) {
598 kn->kn_flags |= EV_EOF;
599 rv = 1;
600 } else {
601 kn->kn_flags &= ~EV_EOF;
602 rv = (kn->kn_data > 0);
603 }
604 if (hint != NOTE_SUBMIT)
605 sounlock(so);
606 return rv;
607 }
608
609 static void
610 filt_fifowdetach(struct knote *kn)
611 {
612 struct socket *so;
613
614 so = (struct socket *)kn->kn_hook;
615 solock(so);
616 SLIST_REMOVE(&so->so_snd.sb_sel.sel_klist, kn, knote, kn_selnext);
617 if (SLIST_EMPTY(&so->so_snd.sb_sel.sel_klist))
618 so->so_snd.sb_flags &= ~SB_KNOTE;
619 sounlock(so);
620 }
621
622 static int
623 filt_fifowrite(struct knote *kn, long hint)
624 {
625 struct socket *so;
626 int rv;
627
628 so = (struct socket *)kn->kn_hook;
629 if (hint != NOTE_SUBMIT)
630 solock(so);
631 kn->kn_data = sbspace(&so->so_snd);
632 if (so->so_state & SS_CANTSENDMORE) {
633 kn->kn_flags |= EV_EOF;
634 rv = 1;
635 } else {
636 kn->kn_flags &= ~EV_EOF;
637 rv = (kn->kn_data >= so->so_snd.sb_lowat);
638 }
639 if (hint != NOTE_SUBMIT)
640 sounlock(so);
641 return rv;
642 }
643
644 static const struct filterops fiforead_filtops =
645 { 1, NULL, filt_fifordetach, filt_fiforead };
646 static const struct filterops fifowrite_filtops =
647 { 1, NULL, filt_fifowdetach, filt_fifowrite };
648
649 /* ARGSUSED */
650 int
651 fifo_kqfilter(void *v)
652 {
653 struct vop_kqfilter_args /* {
654 struct vnode *a_vp;
655 struct knote *a_kn;
656 } */ *ap = v;
657 struct socket *so;
658 struct sockbuf *sb;
659
660 so = (struct socket *)ap->a_vp->v_fifoinfo->fi_readsock;
661 switch (ap->a_kn->kn_filter) {
662 case EVFILT_READ:
663 ap->a_kn->kn_fop = &fiforead_filtops;
664 sb = &so->so_rcv;
665 break;
666 case EVFILT_WRITE:
667 ap->a_kn->kn_fop = &fifowrite_filtops;
668 sb = &so->so_snd;
669 break;
670 default:
671 return (EINVAL);
672 }
673
674 ap->a_kn->kn_hook = so;
675
676 solock(so);
677 SLIST_INSERT_HEAD(&sb->sb_sel.sel_klist, ap->a_kn, kn_selnext);
678 sb->sb_flags |= SB_KNOTE;
679 sounlock(so);
680
681 return (0);
682 }
683