1 | /* $NetBSD: fifo_vnops.c,v 1.77 2014/08/09 05:33:01 rtr 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.77 2014/08/09 05:33:01 rtr 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)) != 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_fallocate_desc, genfs_eopnotsupp }, /* fallocate */ |
637 | { &vop_fdiscard_desc, genfs_eopnotsupp }, /* fdiscard */ |
638 | { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ |
639 | { &vop_poll_desc, fifo_poll }, /* poll */ |
640 | { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */ |
641 | { &vop_revoke_desc, genfs_revoke }, /* revoke */ |
642 | { &vop_mmap_desc, genfs_badop }, /* mmap */ |
643 | { &vop_fsync_desc, genfs_nullop }, /* fsync */ |
644 | { &vop_seek_desc, genfs_badop }, /* seek */ |
645 | { &vop_remove_desc, genfs_badop }, /* remove */ |
646 | { &vop_link_desc, genfs_badop }, /* link */ |
647 | { &vop_rename_desc, genfs_badop }, /* rename */ |
648 | { &vop_mkdir_desc, genfs_badop }, /* mkdir */ |
649 | { &vop_rmdir_desc, genfs_badop }, /* rmdir */ |
650 | { &vop_symlink_desc, genfs_badop }, /* symlink */ |
651 | { &vop_readdir_desc, genfs_badop }, /* readdir */ |
652 | { &vop_readlink_desc, genfs_badop }, /* readlink */ |
653 | { &vop_abortop_desc, genfs_badop }, /* abortop */ |
654 | { &vop_inactive_desc, fifo_inactive }, /* inactive */ |
655 | { &vop_reclaim_desc, genfs_nullop }, /* reclaim */ |
656 | { &vop_lock_desc, genfs_lock }, /* lock */ |
657 | { &vop_unlock_desc, genfs_unlock }, /* unlock */ |
658 | { &vop_bmap_desc, fifo_bmap }, /* bmap */ |
659 | { &vop_strategy_desc, genfs_badop }, /* strategy */ |
660 | { &vop_print_desc, fifo_print }, /* print */ |
661 | { &vop_islocked_desc, genfs_islocked }, /* islocked */ |
662 | { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ |
663 | { &vop_advlock_desc, genfs_einval }, /* advlock */ |
664 | { &vop_bwrite_desc, genfs_nullop }, /* bwrite */ |
665 | { &vop_putpages_desc, genfs_null_putpages }, /* putpages */ |
666 | { NULL, NULL } |
667 | }; |
668 | const struct vnodeopv_desc fifo_vnodeop_opv_desc = |
669 | { &fifo_vnodeop_p, fifo_vnodeop_entries }; |
670 | |