xref: /openbsd-src/sys/miscfs/fifofs/fifo_vnops.c (revision 4e1ee0786f11cc571bd0be17d38e46f635c719fc)
1 /*	$OpenBSD: fifo_vnops.c,v 1.83 2021/10/22 15:11:32 mpi Exp $	*/
2 /*	$NetBSD: fifo_vnops.c,v 1.18 1996/03/16 23:52:42 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1990, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *	@(#)fifo_vnops.c	8.4 (Berkeley) 8/10/94
33  */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/time.h>
38 #include <sys/namei.h>
39 #include <sys/vnode.h>
40 #include <sys/lock.h>
41 #include <sys/protosw.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/stat.h>
45 #include <sys/ioctl.h>
46 #include <sys/fcntl.h>
47 #include <sys/file.h>
48 #include <sys/event.h>
49 #include <sys/errno.h>
50 #include <sys/malloc.h>
51 #include <sys/poll.h>
52 #include <sys/unistd.h>
53 
54 #include <miscfs/fifofs/fifo.h>
55 
56 /*
57  * This structure is associated with the FIFO vnode and stores
58  * the state associated with the FIFO.
59  */
60 struct fifoinfo {
61 	struct socket	*fi_readsock;
62 	struct socket	*fi_writesock;
63 	long		fi_readers;
64 	long		fi_writers;
65 };
66 
67 const struct vops fifo_vops = {
68 	.vop_lookup	= vop_generic_lookup,
69 	.vop_create	= vop_generic_badop,
70 	.vop_mknod	= vop_generic_badop,
71 	.vop_open	= fifo_open,
72 	.vop_close	= fifo_close,
73 	.vop_access	= fifo_ebadf,
74 	.vop_getattr	= fifo_ebadf,
75 	.vop_setattr	= fifo_ebadf,
76 	.vop_read	= fifo_read,
77 	.vop_write	= fifo_write,
78 	.vop_ioctl	= fifo_ioctl,
79 	.vop_poll	= fifo_poll,
80 	.vop_kqfilter	= fifo_kqfilter,
81 	.vop_revoke	= vop_generic_revoke,
82 	.vop_fsync	= nullop,
83 	.vop_remove	= vop_generic_badop,
84 	.vop_link	= vop_generic_badop,
85 	.vop_rename	= vop_generic_badop,
86 	.vop_mkdir	= vop_generic_badop,
87 	.vop_rmdir	= vop_generic_badop,
88 	.vop_symlink	= vop_generic_badop,
89 	.vop_readdir	= vop_generic_badop,
90 	.vop_readlink	= vop_generic_badop,
91 	.vop_abortop	= vop_generic_badop,
92 	.vop_inactive	= fifo_inactive,
93 	.vop_reclaim	= fifo_reclaim,
94 	.vop_lock	= nullop,
95 	.vop_unlock	= nullop,
96 	.vop_islocked	= nullop,
97 	.vop_bmap	= vop_generic_bmap,
98 	.vop_strategy	= vop_generic_badop,
99 	.vop_print	= fifo_print,
100 	.vop_pathconf	= fifo_pathconf,
101 	.vop_advlock	= fifo_advlock,
102 	.vop_bwrite	= nullop
103 };
104 
105 void	filt_fifordetach(struct knote *kn);
106 int	filt_fiforead(struct knote *kn, long hint);
107 int	filt_fiforeadmodify(struct kevent *kev, struct knote *kn);
108 int	filt_fiforeadprocess(struct knote *kn, struct kevent *kev);
109 int	filt_fiforead_common(struct knote *kn, struct socket *so);
110 void	filt_fifowdetach(struct knote *kn);
111 int	filt_fifowrite(struct knote *kn, long hint);
112 int	filt_fifowritemodify(struct kevent *kev, struct knote *kn);
113 int	filt_fifowriteprocess(struct knote *kn, struct kevent *kev);
114 int	filt_fifowrite_common(struct knote *kn, struct socket *so);
115 int	filt_fifoexcept(struct knote *kn, long hint);
116 int	filt_fifoexceptmodify(struct kevent *kev, struct knote *kn);
117 int	filt_fifoexceptprocess(struct knote *kn, struct kevent *kev);
118 int	filt_fifoexcept_common(struct knote *kn, struct socket *so);
119 
120 const struct filterops fiforead_filtops = {
121 	.f_flags	= FILTEROP_ISFD,
122 	.f_attach	= NULL,
123 	.f_detach	= filt_fifordetach,
124 	.f_event	= filt_fiforead,
125 	.f_modify	= filt_fiforeadmodify,
126 	.f_process	= filt_fiforeadprocess,
127 };
128 
129 const struct filterops fifowrite_filtops = {
130 	.f_flags	= FILTEROP_ISFD,
131 	.f_attach	= NULL,
132 	.f_detach	= filt_fifowdetach,
133 	.f_event	= filt_fifowrite,
134 	.f_modify	= filt_fifowritemodify,
135 	.f_process	= filt_fifowriteprocess,
136 };
137 
138 const struct filterops fifoexcept_filtops = {
139 	.f_flags	= FILTEROP_ISFD,
140 	.f_attach	= NULL,
141 	.f_detach	= filt_fifordetach,
142 	.f_event	= filt_fifoexcept,
143 	.f_modify	= filt_fifoexceptmodify,
144 	.f_process	= filt_fifoexceptprocess,
145 };
146 
147 /*
148  * Open called to set up a new instance of a fifo or
149  * to find an active instance of a fifo.
150  */
151 /* ARGSUSED */
152 int
153 fifo_open(void *v)
154 {
155 	struct vop_open_args *ap = v;
156 	struct vnode *vp = ap->a_vp;
157 	struct fifoinfo *fip;
158 	struct socket *rso, *wso;
159 	int s, error;
160 
161 	if ((fip = vp->v_fifoinfo) == NULL) {
162 		fip = malloc(sizeof(*fip), M_VNODE, M_WAITOK);
163 		vp->v_fifoinfo = fip;
164 		if ((error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0)) != 0) {
165 			free(fip, M_VNODE, sizeof *fip);
166 			vp->v_fifoinfo = NULL;
167 			return (error);
168 		}
169 		fip->fi_readsock = rso;
170 		if ((error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0)) != 0) {
171 			(void)soclose(rso, 0);
172 			free(fip, M_VNODE, sizeof *fip);
173 			vp->v_fifoinfo = NULL;
174 			return (error);
175 		}
176 		fip->fi_writesock = wso;
177 		if ((error = soconnect2(wso, rso)) != 0) {
178 			(void)soclose(wso, 0);
179 			(void)soclose(rso, 0);
180 			free(fip, M_VNODE, sizeof *fip);
181 			vp->v_fifoinfo = NULL;
182 			return (error);
183 		}
184 		fip->fi_readers = fip->fi_writers = 0;
185 		s = solock(wso);
186 		wso->so_state |= SS_CANTSENDMORE;
187 		wso->so_snd.sb_lowat = PIPE_BUF;
188 	} else {
189 		rso = fip->fi_readsock;
190 		wso = fip->fi_writesock;
191 		s = solock(wso);
192 	}
193 	if (ap->a_mode & FREAD) {
194 		fip->fi_readers++;
195 		if (fip->fi_readers == 1) {
196 			wso->so_state &= ~SS_CANTSENDMORE;
197 			if (fip->fi_writers > 0)
198 				wakeup(&fip->fi_writers);
199 		}
200 	}
201 	if (ap->a_mode & FWRITE) {
202 		fip->fi_writers++;
203 		if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) {
204 			error = ENXIO;
205 			sounlock(wso, s);
206 			goto bad;
207 		}
208 		if (fip->fi_writers == 1) {
209 			rso->so_state &= ~(SS_CANTRCVMORE|SS_ISDISCONNECTED);
210 			if (fip->fi_readers > 0)
211 				wakeup(&fip->fi_readers);
212 		}
213 	}
214 	sounlock(wso, s);
215 	if ((ap->a_mode & O_NONBLOCK) == 0) {
216 		if ((ap->a_mode & FREAD) && fip->fi_writers == 0) {
217 			VOP_UNLOCK(vp);
218 			error = tsleep_nsec(&fip->fi_readers,
219 			    PCATCH | PSOCK, "fifor", INFSLP);
220 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
221 			if (error)
222 				goto bad;
223 		}
224 		if ((ap->a_mode & FWRITE) && fip->fi_readers == 0) {
225 			VOP_UNLOCK(vp);
226 			error = tsleep_nsec(&fip->fi_writers,
227 			    PCATCH | PSOCK, "fifow", INFSLP);
228 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
229 			if (error)
230 				goto bad;
231 		}
232 	}
233 	return (0);
234 bad:
235 	VOP_CLOSE(vp, ap->a_mode, ap->a_cred, ap->a_p);
236 	return (error);
237 }
238 
239 /*
240  * Vnode op for read
241  */
242 /* ARGSUSED */
243 int
244 fifo_read(void *v)
245 {
246 	struct vop_read_args *ap = v;
247 	struct uio *uio = ap->a_uio;
248 	struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
249 	int error, flags = 0;
250 
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 	if (ap->a_ioflag & IO_NDELAY)
258 		flags |= MSG_DONTWAIT;
259 	VOP_UNLOCK(ap->a_vp);
260 	error = soreceive(rso, NULL, uio, NULL, NULL, &flags, 0);
261 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
262 	if (ap->a_ioflag & IO_NDELAY) {
263 		if (error == EWOULDBLOCK &&
264 		    ap->a_vp->v_fifoinfo->fi_writers == 0)
265 			error = 0;
266 	}
267 	return (error);
268 }
269 
270 /*
271  * Vnode op for write
272  */
273 /* ARGSUSED */
274 int
275 fifo_write(void *v)
276 {
277 	struct vop_write_args *ap = v;
278 	struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
279 	int error, flags = 0;
280 
281 #ifdef DIAGNOSTIC
282 	if (ap->a_uio->uio_rw != UIO_WRITE)
283 		panic("fifo_write mode");
284 #endif
285 	if (ap->a_ioflag & IO_NDELAY)
286 		flags |= MSG_DONTWAIT;
287 	VOP_UNLOCK(ap->a_vp);
288 	error = sosend(wso, NULL, ap->a_uio, NULL, NULL, flags);
289 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
290 	return (error);
291 }
292 
293 /*
294  * Device ioctl operation.
295  */
296 /* ARGSUSED */
297 int
298 fifo_ioctl(void *v)
299 {
300 	struct vop_ioctl_args *ap = v;
301 	struct file filetmp;
302 	int error;
303 
304 	if (ap->a_command == FIONBIO)
305 		return (0);
306 	if (ap->a_fflag & FREAD) {
307 		filetmp.f_data = ap->a_vp->v_fifoinfo->fi_readsock;
308 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
309 		if (error)
310 			return (error);
311 	}
312 	if (ap->a_fflag & FWRITE) {
313 		filetmp.f_data = ap->a_vp->v_fifoinfo->fi_writesock;
314 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
315 		if (error)
316 			return (error);
317 	}
318 	return (0);
319 }
320 
321 /* ARGSUSED */
322 int
323 fifo_poll(void *v)
324 {
325 	struct vop_poll_args *ap = v;
326 	struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
327 	struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
328 	int events = 0;
329 	int revents = 0;
330 	int s;
331 
332 	/*
333 	 * FIFOs don't support out-of-band or high priority data.
334 	 */
335 	s = solock(rso);
336 	if (ap->a_fflag & FREAD)
337 		events |= ap->a_events & (POLLIN | POLLRDNORM);
338 	if (ap->a_fflag & FWRITE)
339 		events |= ap->a_events & (POLLOUT | POLLWRNORM);
340 
341 	if (events & (POLLIN | POLLRDNORM)) {
342 		if (soreadable(rso))
343 			revents |= events & (POLLIN | POLLRDNORM);
344 	}
345 	/* NOTE: POLLHUP and POLLOUT/POLLWRNORM are mutually exclusive */
346 	if ((rso->so_state & SS_ISDISCONNECTED) && !(ap->a_events & POLL_NOHUP)) {
347 		revents |= POLLHUP;
348 	} else if (events & (POLLOUT | POLLWRNORM)) {
349 		if (sowriteable(wso))
350 			revents |= events & (POLLOUT | POLLWRNORM);
351 	}
352 	if (revents == 0) {
353 		/* We want to return POLLHUP even if no valid events set. */
354 		if (events == 0 && !(ap->a_events & POLL_NOHUP))
355 			events = POLLIN;
356 		if (events & (POLLIN | POLLRDNORM)) {
357 			selrecord(ap->a_p, &rso->so_rcv.sb_sel);
358 			rso->so_rcv.sb_flags |= SB_SEL;
359 		}
360 		if (events & (POLLOUT | POLLWRNORM)) {
361 			selrecord(ap->a_p, &wso->so_snd.sb_sel);
362 			wso->so_snd.sb_flags |= SB_SEL;
363 		}
364 	}
365 	sounlock(rso, s);
366 	return (revents);
367 }
368 
369 int
370 fifo_inactive(void *v)
371 {
372 	struct vop_inactive_args *ap = v;
373 
374 	VOP_UNLOCK(ap->a_vp);
375 	return (0);
376 }
377 
378 
379 /*
380  * Device close routine
381  */
382 /* ARGSUSED */
383 int
384 fifo_close(void *v)
385 {
386 	struct vop_close_args *ap = v;
387 	struct vnode *vp = ap->a_vp;
388 	struct fifoinfo *fip = vp->v_fifoinfo;
389 	int s, error1 = 0, error2 = 0;
390 
391 	if (fip == NULL)
392 		return (0);
393 
394 	if (ap->a_fflag & FREAD) {
395 		if (--fip->fi_readers == 0) {
396 			struct socket *wso = fip->fi_writesock;
397 
398 			s = solock(wso);
399 			socantsendmore(wso);
400 			sounlock(wso, s);
401 		}
402 	}
403 	if (ap->a_fflag & FWRITE) {
404 		if (--fip->fi_writers == 0) {
405 			struct socket *rso = fip->fi_readsock;
406 
407 			s = solock(rso);
408 			/* SS_ISDISCONNECTED will result in POLLHUP */
409 			rso->so_state |= SS_ISDISCONNECTED;
410 			socantrcvmore(rso);
411 			sounlock(rso, s);
412 		}
413 	}
414 	if (fip->fi_readers == 0 && fip->fi_writers == 0) {
415 		error1 = soclose(fip->fi_readsock, 0);
416 		error2 = soclose(fip->fi_writesock, 0);
417 		free(fip, M_VNODE, sizeof *fip);
418 		vp->v_fifoinfo = NULL;
419 	}
420 	return (error1 ? error1 : error2);
421 }
422 
423 int
424 fifo_reclaim(void *v)
425 {
426 	struct vop_reclaim_args *ap = v;
427 	struct vnode *vp = ap->a_vp;
428 	struct fifoinfo *fip = vp->v_fifoinfo;
429 
430 	if (fip == NULL)
431 		return (0);
432 
433 	soclose(fip->fi_readsock, 0);
434 	soclose(fip->fi_writesock, 0);
435 	free(fip, M_VNODE, sizeof *fip);
436 	vp->v_fifoinfo = NULL;
437 
438 	return (0);
439 }
440 
441 /*
442  * Print out the contents of a fifo vnode.
443  */
444 int
445 fifo_print(void *v)
446 {
447 	struct vop_print_args *ap = v;
448 
449 	printf("tag VT_NON");
450 	fifo_printinfo(ap->a_vp);
451 	printf("\n");
452 	return 0;
453 }
454 
455 /*
456  * Print out internal contents of a fifo vnode.
457  */
458 void
459 fifo_printinfo(struct vnode *vp)
460 {
461 	struct fifoinfo *fip = vp->v_fifoinfo;
462 
463 	printf(", fifo with %ld readers and %ld writers",
464 		fip->fi_readers, fip->fi_writers);
465 }
466 
467 /*
468  * Return POSIX pathconf information applicable to fifo's.
469  */
470 int
471 fifo_pathconf(void *v)
472 {
473 	struct vop_pathconf_args *ap = v;
474 	int error = 0;
475 
476 	switch (ap->a_name) {
477 	case _PC_LINK_MAX:
478 		*ap->a_retval = LINK_MAX;
479 		break;
480 	case _PC_CHOWN_RESTRICTED:
481 		*ap->a_retval = 1;
482 		break;
483 	case _PC_TIMESTAMP_RESOLUTION:
484 		*ap->a_retval = 1;
485 		break;
486 	default:
487 		error = EINVAL;
488 		break;
489 	}
490 
491 	return (error);
492 }
493 
494 /*
495  * Fifo failed operation
496  */
497 /*ARGSUSED*/
498 int
499 fifo_ebadf(void *v)
500 {
501 
502 	return (EBADF);
503 }
504 
505 /*
506  * Fifo advisory byte-level locks.
507  */
508 /* ARGSUSED */
509 int
510 fifo_advlock(void *v)
511 {
512 	return (EOPNOTSUPP);
513 }
514 
515 int
516 fifo_kqfilter(void *v)
517 {
518 	struct vop_kqfilter_args *ap = v;
519 	struct fifoinfo *fip = ap->a_vp->v_fifoinfo;
520 	struct sockbuf *sb;
521 	struct socket *so;
522 
523 	switch (ap->a_kn->kn_filter) {
524 	case EVFILT_READ:
525 		if (!(ap->a_fflag & FREAD))
526 			return (EINVAL);
527 		ap->a_kn->kn_fop = &fiforead_filtops;
528 		so = fip->fi_readsock;
529 		sb = &so->so_rcv;
530 		break;
531 	case EVFILT_WRITE:
532 		if (!(ap->a_fflag & FWRITE))
533 			return (EINVAL);
534 		ap->a_kn->kn_fop = &fifowrite_filtops;
535 		so = fip->fi_writesock;
536 		sb = &so->so_snd;
537 		break;
538 	case EVFILT_EXCEPT:
539 		ap->a_kn->kn_fop = &fifoexcept_filtops;
540 		so = fip->fi_readsock;
541 		sb = &so->so_rcv;
542 		break;
543 	default:
544 		return (EINVAL);
545 	}
546 
547 	ap->a_kn->kn_hook = so;
548 
549 	klist_insert_locked(&sb->sb_sel.si_note, ap->a_kn);
550 
551 	return (0);
552 }
553 
554 void
555 filt_fifordetach(struct knote *kn)
556 {
557 	struct socket *so = (struct socket *)kn->kn_hook;
558 
559 	klist_remove_locked(&so->so_rcv.sb_sel.si_note, kn);
560 }
561 
562 int
563 filt_fiforead_common(struct knote *kn, struct socket *so)
564 {
565 	int rv;
566 
567 	soassertlocked(so);
568 
569 	kn->kn_data = so->so_rcv.sb_cc;
570 	if (so->so_state & SS_CANTRCVMORE) {
571 		kn->kn_flags |= EV_EOF;
572 		if (kn->kn_flags & __EV_POLL) {
573 			if (so->so_state & SS_ISDISCONNECTED)
574 				kn->kn_flags |= __EV_HUP;
575 		}
576 		rv = 1;
577 	} else {
578 		kn->kn_flags &= ~EV_EOF;
579 		rv = (kn->kn_data > 0);
580 	}
581 
582 	return (rv);
583 }
584 
585 int
586 filt_fiforead(struct knote *kn, long hint)
587 {
588 	struct socket *so = kn->kn_hook;
589 
590 	return (filt_fiforead_common(kn, so));
591 }
592 
593 int
594 filt_fiforeadmodify(struct kevent *kev, struct knote *kn)
595 {
596 	struct socket *so = kn->kn_hook;
597 	int rv, s;
598 
599 	s = solock(so);
600 	knote_modify(kev, kn);
601 	rv = filt_fiforead_common(kn, so);
602 	sounlock(so, s);
603 
604 	return (rv);
605 }
606 
607 int
608 filt_fiforeadprocess(struct knote *kn, struct kevent *kev)
609 {
610 	struct socket *so = kn->kn_hook;
611 	int rv, s;
612 
613 	s = solock(so);
614 	if (kev != NULL && (kn->kn_flags & EV_ONESHOT))
615 		rv = 1;
616 	else
617 		rv = filt_fiforead_common(kn, so);
618 	if (rv != 0)
619 		knote_submit(kn, kev);
620 	sounlock(so, s);
621 
622 	return (rv);
623 }
624 
625 void
626 filt_fifowdetach(struct knote *kn)
627 {
628 	struct socket *so = (struct socket *)kn->kn_hook;
629 
630 	klist_remove_locked(&so->so_snd.sb_sel.si_note, kn);
631 }
632 
633 int
634 filt_fifowrite_common(struct knote *kn, struct socket *so)
635 {
636 	int rv;
637 
638 	soassertlocked(so);
639 
640 	kn->kn_data = sbspace(so, &so->so_snd);
641 	if (so->so_state & SS_CANTSENDMORE) {
642 		kn->kn_flags |= EV_EOF;
643 		rv = 1;
644 	} else {
645 		kn->kn_flags &= ~EV_EOF;
646 		rv = (kn->kn_data >= so->so_snd.sb_lowat);
647 	}
648 
649 	return (rv);
650 }
651 
652 int
653 filt_fifowrite(struct knote *kn, long hint)
654 {
655 	struct socket *so = kn->kn_hook;
656 
657 	return (filt_fifowrite_common(kn, so));
658 }
659 
660 int
661 filt_fifowritemodify(struct kevent *kev, struct knote *kn)
662 {
663 	struct socket *so = kn->kn_hook;
664 	int rv, s;
665 
666 	s = solock(so);
667 	knote_modify(kev, kn);
668 	rv = filt_fifowrite_common(kn, so);
669 	sounlock(so, s);
670 
671 	return (rv);
672 }
673 
674 int
675 filt_fifowriteprocess(struct knote *kn, struct kevent *kev)
676 {
677 	struct socket *so = kn->kn_hook;
678 	int rv, s;
679 
680 	s = solock(so);
681 	if (kev != NULL && (kn->kn_flags & EV_ONESHOT))
682 		rv = 1;
683 	else
684 		rv = filt_fifowrite_common(kn, so);
685 	if (rv != 0)
686 		knote_submit(kn, kev);
687 	sounlock(so, s);
688 
689 	return (rv);
690 }
691 
692 int
693 filt_fifoexcept_common(struct knote *kn, struct socket *so)
694 {
695 	int rv = 0;
696 
697 	soassertlocked(so);
698 
699 	if (so->so_state & SS_CANTRCVMORE) {
700 		kn->kn_flags |= EV_EOF;
701 		if (kn->kn_flags & __EV_POLL) {
702 			if (so->so_state & SS_ISDISCONNECTED)
703 				kn->kn_flags |= __EV_HUP;
704 		}
705 		rv = 1;
706 	}
707 
708 	return (rv);
709 }
710 
711 int
712 filt_fifoexcept(struct knote *kn, long hint)
713 {
714 	struct socket *so = kn->kn_hook;
715 
716 	return (filt_fifoexcept_common(kn, so));
717 }
718 
719 int
720 filt_fifoexceptmodify(struct kevent *kev, struct knote *kn)
721 {
722 	struct socket *so = kn->kn_hook;
723 	int rv, s;
724 
725 	s = solock(so);
726 	knote_modify(kev, kn);
727 	rv = filt_fifoexcept_common(kn, so);
728 	sounlock(so, s);
729 
730 	return (rv);
731 }
732 
733 int
734 filt_fifoexceptprocess(struct knote *kn, struct kevent *kev)
735 {
736 	struct socket *so = kn->kn_hook;
737 	int rv, s;
738 
739 	s = solock(so);
740 	if (kev != NULL && (kn->kn_flags & EV_ONESHOT))
741 		rv = 1;
742 	else
743 		rv = filt_fifoexcept_common(kn, so);
744 	if (rv != 0)
745 		knote_submit(kn, kev);
746 	sounlock(so, s);
747 
748 	return (rv);
749 }
750