xref: /openbsd/sys/miscfs/fifofs/fifo_vnops.c (revision 5a0ec814)
1 /*	$OpenBSD: fifo_vnops.c,v 1.108 2024/10/18 05:52:32 miod 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/unistd.h>
52 
53 #include <miscfs/fifofs/fifo.h>
54 
55 /*
56  * This structure is associated with the FIFO vnode and stores
57  * the state associated with the FIFO.
58  */
59 struct fifoinfo {
60 	struct socket	*fi_readsock;
61 	struct socket	*fi_writesock;
62 	long		fi_readers;
63 	long		fi_writers;
64 };
65 
66 const struct vops fifo_vops = {
67 	.vop_lookup	= vop_generic_lookup,
68 	.vop_create	= vop_generic_badop,
69 	.vop_mknod	= vop_generic_badop,
70 	.vop_open	= fifo_open,
71 	.vop_close	= fifo_close,
72 	.vop_access	= fifo_ebadf,
73 	.vop_getattr	= fifo_ebadf,
74 	.vop_setattr	= fifo_ebadf,
75 	.vop_read	= fifo_read,
76 	.vop_write	= fifo_write,
77 	.vop_ioctl	= fifo_ioctl,
78 	.vop_kqfilter	= fifo_kqfilter,
79 	.vop_revoke	= vop_generic_revoke,
80 	.vop_fsync	= nullop,
81 	.vop_remove	= vop_generic_badop,
82 	.vop_link	= vop_generic_badop,
83 	.vop_rename	= vop_generic_badop,
84 	.vop_mkdir	= vop_generic_badop,
85 	.vop_rmdir	= vop_generic_badop,
86 	.vop_symlink	= vop_generic_badop,
87 	.vop_readdir	= vop_generic_badop,
88 	.vop_readlink	= vop_generic_badop,
89 	.vop_abortop	= vop_generic_badop,
90 	.vop_inactive	= fifo_inactive,
91 	.vop_reclaim	= fifo_reclaim,
92 	.vop_lock	= nullop,
93 	.vop_unlock	= nullop,
94 	.vop_islocked	= nullop,
95 	.vop_bmap	= vop_generic_bmap,
96 	.vop_strategy	= vop_generic_badop,
97 	.vop_print	= fifo_print,
98 	.vop_pathconf	= fifo_pathconf,
99 	.vop_advlock	= fifo_advlock,
100 	.vop_bwrite	= nullop
101 };
102 
103 void	filt_fifordetach(struct knote *kn);
104 int	filt_fiforead(struct knote *kn, long hint);
105 void	filt_fifowdetach(struct knote *kn);
106 int	filt_fifowrite(struct knote *kn, long hint);
107 int	filt_fifoexcept(struct knote *kn, long hint);
108 int	filt_fiformodify(struct kevent *kev, struct knote *kn);
109 int	filt_fiforprocess(struct knote *kn, struct kevent *kev);
110 int	filt_fifowmodify(struct kevent *kev, struct knote *kn);
111 int	filt_fifowprocess(struct knote *kn, struct kevent *kev);
112 
113 const struct filterops fiforead_filtops = {
114 	.f_flags	= FILTEROP_ISFD | FILTEROP_MPSAFE,
115 	.f_attach	= NULL,
116 	.f_detach	= filt_fifordetach,
117 	.f_event	= filt_fiforead,
118 	.f_modify	= filt_fiformodify,
119 	.f_process	= filt_fiforprocess,
120 };
121 
122 const struct filterops fifowrite_filtops = {
123 	.f_flags	= FILTEROP_ISFD | FILTEROP_MPSAFE,
124 	.f_attach	= NULL,
125 	.f_detach	= filt_fifowdetach,
126 	.f_event	= filt_fifowrite,
127 	.f_modify	= filt_fifowmodify,
128 	.f_process	= filt_fifowprocess,
129 };
130 
131 const struct filterops fifoexcept_filtops = {
132 	.f_flags	= FILTEROP_ISFD | FILTEROP_MPSAFE,
133 	.f_attach	= NULL,
134 	.f_detach	= filt_fifordetach,
135 	.f_event	= filt_fifoexcept,
136 	.f_modify	= filt_fiformodify,
137 	.f_process	= filt_fiforprocess,
138 };
139 
140 /*
141  * Open called to set up a new instance of a fifo or
142  * to find an active instance of a fifo.
143  */
144 int
fifo_open(void * v)145 fifo_open(void *v)
146 {
147 	struct vop_open_args *ap = v;
148 	struct vnode *vp = ap->a_vp;
149 	struct fifoinfo *fip;
150 	struct socket *rso, *wso;
151 	int error;
152 
153 	if ((fip = vp->v_fifoinfo) == NULL) {
154 		fip = malloc(sizeof(*fip), M_VNODE, M_WAITOK);
155 		vp->v_fifoinfo = fip;
156 		if ((error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0)) != 0) {
157 			free(fip, M_VNODE, sizeof *fip);
158 			vp->v_fifoinfo = NULL;
159 			return (error);
160 		}
161 		fip->fi_readsock = rso;
162 		if ((error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0)) != 0) {
163 			(void)soclose(rso, 0);
164 			free(fip, M_VNODE, sizeof *fip);
165 			vp->v_fifoinfo = NULL;
166 			return (error);
167 		}
168 		fip->fi_writesock = wso;
169 		if ((error = soconnect2(wso, rso)) != 0) {
170 			(void)soclose(wso, 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_readers = fip->fi_writers = 0;
177 		/*
178 		 * Should take both solock() and `sb_mtx' mutex for
179 		 * SS_CANTSENDMORE flag modifications.
180 		 */
181 		solock(wso);
182 		mtx_enter(&wso->so_snd.sb_mtx);
183 		wso->so_snd.sb_state |= SS_CANTSENDMORE;
184 		wso->so_snd.sb_lowat = PIPE_BUF;
185 		mtx_leave(&wso->so_snd.sb_mtx);
186 		sounlock(wso);
187 	} else {
188 		rso = fip->fi_readsock;
189 		wso = fip->fi_writesock;
190 	}
191 	if (ap->a_mode & FREAD) {
192 		fip->fi_readers++;
193 		if (fip->fi_readers == 1) {
194 			solock(wso);
195 			mtx_enter(&wso->so_snd.sb_mtx);
196 			wso->so_snd.sb_state &= ~SS_CANTSENDMORE;
197 			mtx_leave(&wso->so_snd.sb_mtx);
198 			sounlock(wso);
199 			if (fip->fi_writers > 0)
200 				wakeup(&fip->fi_writers);
201 		}
202 	}
203 	if (ap->a_mode & FWRITE) {
204 		fip->fi_writers++;
205 		if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) {
206 			error = ENXIO;
207 			goto bad;
208 		}
209 		if (fip->fi_writers == 1) {
210 			solock(rso);
211 			rso->so_state &= ~SS_ISDISCONNECTED;
212 			mtx_enter(&rso->so_rcv.sb_mtx);
213 			rso->so_rcv.sb_state &= ~SS_CANTRCVMORE;
214 			mtx_leave(&rso->so_rcv.sb_mtx);
215 			sounlock(rso);
216 			if (fip->fi_readers > 0)
217 				wakeup(&fip->fi_readers);
218 		}
219 	}
220 	if ((ap->a_mode & O_NONBLOCK) == 0) {
221 		if ((ap->a_mode & FREAD) && fip->fi_writers == 0) {
222 			VOP_UNLOCK(vp);
223 			error = tsleep_nsec(&fip->fi_readers,
224 			    PCATCH | PSOCK, "fifor", INFSLP);
225 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
226 			if (error)
227 				goto bad;
228 		}
229 		if ((ap->a_mode & FWRITE) && fip->fi_readers == 0) {
230 			VOP_UNLOCK(vp);
231 			error = tsleep_nsec(&fip->fi_writers,
232 			    PCATCH | PSOCK, "fifow", INFSLP);
233 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
234 			if (error)
235 				goto bad;
236 		}
237 	}
238 	return (0);
239 bad:
240 	VOP_CLOSE(vp, ap->a_mode, ap->a_cred, ap->a_p);
241 	return (error);
242 }
243 
244 /*
245  * Vnode op for read
246  */
247 int
fifo_read(void * v)248 fifo_read(void *v)
249 {
250 	struct vop_read_args *ap = v;
251 	struct uio *uio = ap->a_uio;
252 	struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
253 	int error, flags = 0;
254 
255 #ifdef DIAGNOSTIC
256 	if (uio->uio_rw != UIO_READ)
257 		panic("fifo_read mode");
258 #endif
259 	if (uio->uio_resid == 0)
260 		return (0);
261 	if (ap->a_ioflag & IO_NDELAY)
262 		flags |= MSG_DONTWAIT;
263 	VOP_UNLOCK(ap->a_vp);
264 	error = soreceive(rso, NULL, uio, NULL, NULL, &flags, 0);
265 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
266 	if (ap->a_ioflag & IO_NDELAY) {
267 		if (error == EWOULDBLOCK &&
268 		    ap->a_vp->v_fifoinfo->fi_writers == 0)
269 			error = 0;
270 	}
271 	return (error);
272 }
273 
274 /*
275  * Vnode op for write
276  */
277 int
fifo_write(void * v)278 fifo_write(void *v)
279 {
280 	struct vop_write_args *ap = v;
281 	struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
282 	int error, flags = 0;
283 
284 #ifdef DIAGNOSTIC
285 	if (ap->a_uio->uio_rw != UIO_WRITE)
286 		panic("fifo_write mode");
287 #endif
288 	if (ap->a_ioflag & IO_NDELAY)
289 		flags |= MSG_DONTWAIT;
290 	VOP_UNLOCK(ap->a_vp);
291 	error = sosend(wso, NULL, ap->a_uio, NULL, NULL, flags);
292 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
293 	return (error);
294 }
295 
296 /*
297  * Device ioctl operation.
298  */
299 int
fifo_ioctl(void * v)300 fifo_ioctl(void *v)
301 {
302 	struct vop_ioctl_args *ap = v;
303 	struct file filetmp;
304 	int error;
305 
306 	if (ap->a_command == FIONBIO)
307 		return (0);
308 	if (ap->a_fflag & FREAD) {
309 		filetmp.f_data = ap->a_vp->v_fifoinfo->fi_readsock;
310 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
311 		if (error)
312 			return (error);
313 	}
314 	if (ap->a_fflag & FWRITE) {
315 		filetmp.f_data = ap->a_vp->v_fifoinfo->fi_writesock;
316 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
317 		if (error)
318 			return (error);
319 	}
320 	return (0);
321 }
322 
323 int
fifo_inactive(void * v)324 fifo_inactive(void *v)
325 {
326 	struct vop_inactive_args *ap = v;
327 
328 	VOP_UNLOCK(ap->a_vp);
329 	return (0);
330 }
331 
332 
333 /*
334  * Device close routine
335  */
336 int
fifo_close(void * v)337 fifo_close(void *v)
338 {
339 	struct vop_close_args *ap = v;
340 	struct vnode *vp = ap->a_vp;
341 	struct fifoinfo *fip = vp->v_fifoinfo;
342 	int error1 = 0, error2 = 0;
343 
344 	if (fip == NULL)
345 		return (0);
346 
347 	if (ap->a_fflag & FREAD) {
348 		if (--fip->fi_readers == 0) {
349 			struct socket *wso = fip->fi_writesock;
350 
351 			solock(wso);
352 			socantsendmore(wso);
353 			sounlock(wso);
354 		}
355 	}
356 	if (ap->a_fflag & FWRITE) {
357 		if (--fip->fi_writers == 0) {
358 			struct socket *rso = fip->fi_readsock;
359 
360 			solock(rso);
361 			/* SS_ISDISCONNECTED will result in POLLHUP */
362 			rso->so_state |= SS_ISDISCONNECTED;
363 			socantrcvmore(rso);
364 			sounlock(rso);
365 		}
366 	}
367 	if (fip->fi_readers == 0 && fip->fi_writers == 0) {
368 		error1 = soclose(fip->fi_readsock, 0);
369 		error2 = soclose(fip->fi_writesock, 0);
370 		free(fip, M_VNODE, sizeof *fip);
371 		vp->v_fifoinfo = NULL;
372 	}
373 	return (error1 ? error1 : error2);
374 }
375 
376 int
fifo_reclaim(void * v)377 fifo_reclaim(void *v)
378 {
379 	struct vop_reclaim_args *ap = v;
380 	struct vnode *vp = ap->a_vp;
381 	struct fifoinfo *fip = vp->v_fifoinfo;
382 
383 	if (fip == NULL)
384 		return (0);
385 
386 	soclose(fip->fi_readsock, 0);
387 	soclose(fip->fi_writesock, 0);
388 	free(fip, M_VNODE, sizeof *fip);
389 	vp->v_fifoinfo = NULL;
390 
391 	return (0);
392 }
393 
394 /*
395  * Print out the contents of a fifo vnode.
396  */
397 int
fifo_print(void * v)398 fifo_print(void *v)
399 {
400 #if defined(DEBUG) || defined(DIAGNOSTIC) || defined(VFSLCKDEBUG)
401 	struct vop_print_args *ap = v;
402 
403 	printf("tag VT_NON");
404 	fifo_printinfo(ap->a_vp);
405 	printf("\n");
406 #endif
407 	return 0;
408 }
409 
410 #if defined(DEBUG) || defined(DIAGNOSTIC) || defined(VFSLCKDEBUG)
411 /*
412  * Print out internal contents of a fifo vnode.
413  */
414 void
fifo_printinfo(struct vnode * vp)415 fifo_printinfo(struct vnode *vp)
416 {
417 	struct fifoinfo *fip = vp->v_fifoinfo;
418 
419 	printf(", fifo with %ld readers and %ld writers",
420 		fip->fi_readers, fip->fi_writers);
421 }
422 #endif
423 
424 /*
425  * Return POSIX pathconf information applicable to fifo's.
426  */
427 int
fifo_pathconf(void * v)428 fifo_pathconf(void *v)
429 {
430 	struct vop_pathconf_args *ap = v;
431 	int error = 0;
432 
433 	switch (ap->a_name) {
434 	case _PC_LINK_MAX:
435 		*ap->a_retval = LINK_MAX;
436 		break;
437 	case _PC_CHOWN_RESTRICTED:
438 		*ap->a_retval = 1;
439 		break;
440 	case _PC_TIMESTAMP_RESOLUTION:
441 		*ap->a_retval = 1;
442 		break;
443 	default:
444 		error = EINVAL;
445 		break;
446 	}
447 
448 	return (error);
449 }
450 
451 /*
452  * Fifo failed operation
453  */
454 int
fifo_ebadf(void * v)455 fifo_ebadf(void *v)
456 {
457 
458 	return (EBADF);
459 }
460 
461 /*
462  * Fifo advisory byte-level locks.
463  */
464 int
fifo_advlock(void * v)465 fifo_advlock(void *v)
466 {
467 	return (EOPNOTSUPP);
468 }
469 
470 int
fifo_kqfilter(void * v)471 fifo_kqfilter(void *v)
472 {
473 	struct vop_kqfilter_args *ap = v;
474 	struct fifoinfo *fip = ap->a_vp->v_fifoinfo;
475 	struct sockbuf *sb;
476 	struct socket *so;
477 
478 	switch (ap->a_kn->kn_filter) {
479 	case EVFILT_READ:
480 		if (!(ap->a_fflag & FREAD))
481 			return (EINVAL);
482 		ap->a_kn->kn_fop = &fiforead_filtops;
483 		so = fip->fi_readsock;
484 		sb = &so->so_rcv;
485 		break;
486 	case EVFILT_WRITE:
487 		if (!(ap->a_fflag & FWRITE)) {
488 			/* Tell upper layer to ask for POLLUP only */
489 			if (ap->a_kn->kn_flags & (__EV_POLL | __EV_SELECT))
490 				return (EPERM);
491 			return (EINVAL);
492 		}
493 		ap->a_kn->kn_fop = &fifowrite_filtops;
494 		so = fip->fi_writesock;
495 		sb = &so->so_snd;
496 		break;
497 	case EVFILT_EXCEPT:
498 		if (ap->a_kn->kn_flags & __EV_SELECT) {
499 			/* Prevent triggering exceptfds. */
500 			return (EPERM);
501 		}
502 		if ((ap->a_kn->kn_flags & __EV_POLL) == 0) {
503 			/* Disallow usage through kevent(2). */
504 			return (EINVAL);
505 		}
506 		ap->a_kn->kn_fop = &fifoexcept_filtops;
507 		so = fip->fi_readsock;
508 		sb = &so->so_rcv;
509 		break;
510 	default:
511 		return (EINVAL);
512 	}
513 
514 	ap->a_kn->kn_hook = so;
515 
516 	klist_insert(&sb->sb_klist, ap->a_kn);
517 
518 	return (0);
519 }
520 
521 void
filt_fifordetach(struct knote * kn)522 filt_fifordetach(struct knote *kn)
523 {
524 	struct socket *so = (struct socket *)kn->kn_hook;
525 
526 	klist_remove(&so->so_rcv.sb_klist, kn);
527 }
528 
529 int
filt_fiforead(struct knote * kn,long hint)530 filt_fiforead(struct knote *kn, long hint)
531 {
532 	struct socket *so = kn->kn_hook;
533 	int rv;
534 
535 	MUTEX_ASSERT_LOCKED(&so->so_rcv.sb_mtx);
536 
537 	kn->kn_data = so->so_rcv.sb_cc;
538 	if (so->so_rcv.sb_state & SS_CANTRCVMORE) {
539 		kn->kn_flags |= EV_EOF;
540 		if (kn->kn_flags & __EV_POLL) {
541 			if (so->so_state & SS_ISDISCONNECTED)
542 				kn->kn_flags |= __EV_HUP;
543 			else
544 				kn->kn_flags &= ~__EV_HUP;
545 		}
546 		rv = 1;
547 	} else {
548 		kn->kn_flags &= ~(EV_EOF | __EV_HUP);
549 		rv = (kn->kn_data > 0);
550 	}
551 
552 	return (rv);
553 }
554 
555 void
filt_fifowdetach(struct knote * kn)556 filt_fifowdetach(struct knote *kn)
557 {
558 	struct socket *so = (struct socket *)kn->kn_hook;
559 
560 	klist_remove(&so->so_snd.sb_klist, kn);
561 }
562 
563 int
filt_fifowrite(struct knote * kn,long hint)564 filt_fifowrite(struct knote *kn, long hint)
565 {
566 	struct socket *so = kn->kn_hook;
567 	int rv;
568 
569 	MUTEX_ASSERT_LOCKED(&so->so_snd.sb_mtx);
570 
571 	kn->kn_data = sbspace_locked(so, &so->so_snd);
572 	if (so->so_snd.sb_state & SS_CANTSENDMORE) {
573 		kn->kn_flags |= EV_EOF;
574 		rv = 1;
575 	} else {
576 		kn->kn_flags &= ~EV_EOF;
577 		rv = (kn->kn_data >= so->so_snd.sb_lowat);
578 	}
579 
580 	return (rv);
581 }
582 
583 int
filt_fifoexcept(struct knote * kn,long hint)584 filt_fifoexcept(struct knote *kn, long hint)
585 {
586 	struct socket *so = kn->kn_hook;
587 	int rv = 0;
588 
589 	MUTEX_ASSERT_LOCKED(&so->so_rcv.sb_mtx);
590 
591 	if (kn->kn_flags & __EV_POLL) {
592 		if (so->so_state & SS_ISDISCONNECTED) {
593 			kn->kn_flags |= __EV_HUP;
594 			rv = 1;
595 		} else {
596 			kn->kn_flags &= ~__EV_HUP;
597 		}
598 	}
599 
600 	return (rv);
601 }
602 
603 int
filt_fiformodify(struct kevent * kev,struct knote * kn)604 filt_fiformodify(struct kevent *kev, struct knote *kn)
605 {
606 	struct socket *so = kn->kn_hook;
607 	int rv;
608 
609 	solock(so);
610 	mtx_enter(&so->so_rcv.sb_mtx);
611 	rv = knote_modify(kev, kn);
612 	mtx_leave(&so->so_rcv.sb_mtx);
613 	sounlock(so);
614 
615 	return (rv);
616 }
617 
618 int
filt_fiforprocess(struct knote * kn,struct kevent * kev)619 filt_fiforprocess(struct knote *kn, struct kevent *kev)
620 {
621 	struct socket *so = kn->kn_hook;
622 	int rv;
623 
624 	solock(so);
625 	mtx_enter(&so->so_rcv.sb_mtx);
626 	rv = knote_process(kn, kev);
627 	mtx_leave(&so->so_rcv.sb_mtx);
628 	sounlock(so);
629 
630 	return (rv);
631 }
632 
633 int
filt_fifowmodify(struct kevent * kev,struct knote * kn)634 filt_fifowmodify(struct kevent *kev, struct knote *kn)
635 {
636 	struct socket *so = kn->kn_hook;
637 	int rv;
638 
639 	mtx_enter(&so->so_snd.sb_mtx);
640 	rv = knote_modify(kev, kn);
641 	mtx_leave(&so->so_snd.sb_mtx);
642 
643 	return (rv);
644 }
645 
646 int
filt_fifowprocess(struct knote * kn,struct kevent * kev)647 filt_fifowprocess(struct knote *kn, struct kevent *kev)
648 {
649 	struct socket *so = kn->kn_hook;
650 	int rv;
651 
652 	mtx_enter(&so->so_snd.sb_mtx);
653 	rv = knote_process(kn, kev);
654 	mtx_leave(&so->so_snd.sb_mtx);
655 
656 	return (rv);
657 }
658