xref: /openbsd-src/sys/miscfs/fifofs/fifo_vnops.c (revision 8550894424f8a4aa4aafb6cd57229dd6ed7cd9dd)
1 /*	$OpenBSD: fifo_vnops.c,v 1.100 2023/01/22 12:05:44 mvs 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_fifomodify(struct kevent *kev, struct knote *kn);
109 int	filt_fifoprocess(struct knote *kn, struct kevent *kev);
110 
111 const struct filterops fiforead_filtops = {
112 	.f_flags	= FILTEROP_ISFD | FILTEROP_MPSAFE,
113 	.f_attach	= NULL,
114 	.f_detach	= filt_fifordetach,
115 	.f_event	= filt_fiforead,
116 	.f_modify	= filt_fifomodify,
117 	.f_process	= filt_fifoprocess,
118 };
119 
120 const struct filterops fifowrite_filtops = {
121 	.f_flags	= FILTEROP_ISFD | FILTEROP_MPSAFE,
122 	.f_attach	= NULL,
123 	.f_detach	= filt_fifowdetach,
124 	.f_event	= filt_fifowrite,
125 	.f_modify	= filt_fifomodify,
126 	.f_process	= filt_fifoprocess,
127 };
128 
129 const struct filterops fifoexcept_filtops = {
130 	.f_flags	= FILTEROP_ISFD | FILTEROP_MPSAFE,
131 	.f_attach	= NULL,
132 	.f_detach	= filt_fifordetach,
133 	.f_event	= filt_fifoexcept,
134 	.f_modify	= filt_fifomodify,
135 	.f_process	= filt_fifoprocess,
136 };
137 
138 /*
139  * Open called to set up a new instance of a fifo or
140  * to find an active instance of a fifo.
141  */
142 /* ARGSUSED */
143 int
144 fifo_open(void *v)
145 {
146 	struct vop_open_args *ap = v;
147 	struct vnode *vp = ap->a_vp;
148 	struct fifoinfo *fip;
149 	struct socket *rso, *wso;
150 	int error;
151 
152 	if ((fip = vp->v_fifoinfo) == NULL) {
153 		fip = malloc(sizeof(*fip), M_VNODE, M_WAITOK);
154 		vp->v_fifoinfo = fip;
155 		if ((error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0)) != 0) {
156 			free(fip, M_VNODE, sizeof *fip);
157 			vp->v_fifoinfo = NULL;
158 			return (error);
159 		}
160 		fip->fi_readsock = rso;
161 		if ((error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0)) != 0) {
162 			(void)soclose(rso, 0);
163 			free(fip, M_VNODE, sizeof *fip);
164 			vp->v_fifoinfo = NULL;
165 			return (error);
166 		}
167 		fip->fi_writesock = wso;
168 		if ((error = soconnect2(wso, rso)) != 0) {
169 			(void)soclose(wso, 0);
170 			(void)soclose(rso, 0);
171 			free(fip, M_VNODE, sizeof *fip);
172 			vp->v_fifoinfo = NULL;
173 			return (error);
174 		}
175 		fip->fi_readers = fip->fi_writers = 0;
176 		solock(wso);
177 		wso->so_snd.sb_state |= SS_CANTSENDMORE;
178 		wso->so_snd.sb_lowat = PIPE_BUF;
179 		sounlock(wso);
180 	} else {
181 		rso = fip->fi_readsock;
182 		wso = fip->fi_writesock;
183 	}
184 	if (ap->a_mode & FREAD) {
185 		fip->fi_readers++;
186 		if (fip->fi_readers == 1) {
187 			solock(wso);
188 			wso->so_snd.sb_state &= ~SS_CANTSENDMORE;
189 			sounlock(wso);
190 			if (fip->fi_writers > 0)
191 				wakeup(&fip->fi_writers);
192 		}
193 	}
194 	if (ap->a_mode & FWRITE) {
195 		fip->fi_writers++;
196 		if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) {
197 			error = ENXIO;
198 			goto bad;
199 		}
200 		if (fip->fi_writers == 1) {
201 			solock(rso);
202 			rso->so_state &= ~SS_ISDISCONNECTED;
203 			rso->so_rcv.sb_state &= ~SS_CANTRCVMORE;
204 			sounlock(rso);
205 			if (fip->fi_readers > 0)
206 				wakeup(&fip->fi_readers);
207 		}
208 	}
209 	if ((ap->a_mode & O_NONBLOCK) == 0) {
210 		if ((ap->a_mode & FREAD) && fip->fi_writers == 0) {
211 			VOP_UNLOCK(vp);
212 			error = tsleep_nsec(&fip->fi_readers,
213 			    PCATCH | PSOCK, "fifor", INFSLP);
214 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
215 			if (error)
216 				goto bad;
217 		}
218 		if ((ap->a_mode & FWRITE) && fip->fi_readers == 0) {
219 			VOP_UNLOCK(vp);
220 			error = tsleep_nsec(&fip->fi_writers,
221 			    PCATCH | PSOCK, "fifow", INFSLP);
222 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
223 			if (error)
224 				goto bad;
225 		}
226 	}
227 	return (0);
228 bad:
229 	VOP_CLOSE(vp, ap->a_mode, ap->a_cred, ap->a_p);
230 	return (error);
231 }
232 
233 /*
234  * Vnode op for read
235  */
236 /* ARGSUSED */
237 int
238 fifo_read(void *v)
239 {
240 	struct vop_read_args *ap = v;
241 	struct uio *uio = ap->a_uio;
242 	struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
243 	int error, flags = 0;
244 
245 #ifdef DIAGNOSTIC
246 	if (uio->uio_rw != UIO_READ)
247 		panic("fifo_read mode");
248 #endif
249 	if (uio->uio_resid == 0)
250 		return (0);
251 	if (ap->a_ioflag & IO_NDELAY)
252 		flags |= MSG_DONTWAIT;
253 	VOP_UNLOCK(ap->a_vp);
254 	error = soreceive(rso, NULL, uio, NULL, NULL, &flags, 0);
255 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
256 	if (ap->a_ioflag & IO_NDELAY) {
257 		if (error == EWOULDBLOCK &&
258 		    ap->a_vp->v_fifoinfo->fi_writers == 0)
259 			error = 0;
260 	}
261 	return (error);
262 }
263 
264 /*
265  * Vnode op for write
266  */
267 /* ARGSUSED */
268 int
269 fifo_write(void *v)
270 {
271 	struct vop_write_args *ap = v;
272 	struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
273 	int error, flags = 0;
274 
275 #ifdef DIAGNOSTIC
276 	if (ap->a_uio->uio_rw != UIO_WRITE)
277 		panic("fifo_write mode");
278 #endif
279 	if (ap->a_ioflag & IO_NDELAY)
280 		flags |= MSG_DONTWAIT;
281 	VOP_UNLOCK(ap->a_vp);
282 	error = sosend(wso, NULL, ap->a_uio, NULL, NULL, flags);
283 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
284 	return (error);
285 }
286 
287 /*
288  * Device ioctl operation.
289  */
290 /* ARGSUSED */
291 int
292 fifo_ioctl(void *v)
293 {
294 	struct vop_ioctl_args *ap = v;
295 	struct file filetmp;
296 	int error;
297 
298 	if (ap->a_command == FIONBIO)
299 		return (0);
300 	if (ap->a_fflag & FREAD) {
301 		filetmp.f_data = ap->a_vp->v_fifoinfo->fi_readsock;
302 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
303 		if (error)
304 			return (error);
305 	}
306 	if (ap->a_fflag & FWRITE) {
307 		filetmp.f_data = ap->a_vp->v_fifoinfo->fi_writesock;
308 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
309 		if (error)
310 			return (error);
311 	}
312 	return (0);
313 }
314 
315 int
316 fifo_inactive(void *v)
317 {
318 	struct vop_inactive_args *ap = v;
319 
320 	VOP_UNLOCK(ap->a_vp);
321 	return (0);
322 }
323 
324 
325 /*
326  * Device close routine
327  */
328 /* ARGSUSED */
329 int
330 fifo_close(void *v)
331 {
332 	struct vop_close_args *ap = v;
333 	struct vnode *vp = ap->a_vp;
334 	struct fifoinfo *fip = vp->v_fifoinfo;
335 	int error1 = 0, error2 = 0;
336 
337 	if (fip == NULL)
338 		return (0);
339 
340 	if (ap->a_fflag & FREAD) {
341 		if (--fip->fi_readers == 0) {
342 			struct socket *wso = fip->fi_writesock;
343 
344 			solock(wso);
345 			socantsendmore(wso);
346 			sounlock(wso);
347 		}
348 	}
349 	if (ap->a_fflag & FWRITE) {
350 		if (--fip->fi_writers == 0) {
351 			struct socket *rso = fip->fi_readsock;
352 
353 			solock(rso);
354 			/* SS_ISDISCONNECTED will result in POLLHUP */
355 			rso->so_state |= SS_ISDISCONNECTED;
356 			socantrcvmore(rso);
357 			sounlock(rso);
358 		}
359 	}
360 	if (fip->fi_readers == 0 && fip->fi_writers == 0) {
361 		error1 = soclose(fip->fi_readsock, 0);
362 		error2 = soclose(fip->fi_writesock, 0);
363 		free(fip, M_VNODE, sizeof *fip);
364 		vp->v_fifoinfo = NULL;
365 	}
366 	return (error1 ? error1 : error2);
367 }
368 
369 int
370 fifo_reclaim(void *v)
371 {
372 	struct vop_reclaim_args *ap = v;
373 	struct vnode *vp = ap->a_vp;
374 	struct fifoinfo *fip = vp->v_fifoinfo;
375 
376 	if (fip == NULL)
377 		return (0);
378 
379 	soclose(fip->fi_readsock, 0);
380 	soclose(fip->fi_writesock, 0);
381 	free(fip, M_VNODE, sizeof *fip);
382 	vp->v_fifoinfo = NULL;
383 
384 	return (0);
385 }
386 
387 /*
388  * Print out the contents of a fifo vnode.
389  */
390 int
391 fifo_print(void *v)
392 {
393 	struct vop_print_args *ap = v;
394 
395 	printf("tag VT_NON");
396 	fifo_printinfo(ap->a_vp);
397 	printf("\n");
398 	return 0;
399 }
400 
401 /*
402  * Print out internal contents of a fifo vnode.
403  */
404 void
405 fifo_printinfo(struct vnode *vp)
406 {
407 	struct fifoinfo *fip = vp->v_fifoinfo;
408 
409 	printf(", fifo with %ld readers and %ld writers",
410 		fip->fi_readers, fip->fi_writers);
411 }
412 
413 /*
414  * Return POSIX pathconf information applicable to fifo's.
415  */
416 int
417 fifo_pathconf(void *v)
418 {
419 	struct vop_pathconf_args *ap = v;
420 	int error = 0;
421 
422 	switch (ap->a_name) {
423 	case _PC_LINK_MAX:
424 		*ap->a_retval = LINK_MAX;
425 		break;
426 	case _PC_CHOWN_RESTRICTED:
427 		*ap->a_retval = 1;
428 		break;
429 	case _PC_TIMESTAMP_RESOLUTION:
430 		*ap->a_retval = 1;
431 		break;
432 	default:
433 		error = EINVAL;
434 		break;
435 	}
436 
437 	return (error);
438 }
439 
440 /*
441  * Fifo failed operation
442  */
443 /*ARGSUSED*/
444 int
445 fifo_ebadf(void *v)
446 {
447 
448 	return (EBADF);
449 }
450 
451 /*
452  * Fifo advisory byte-level locks.
453  */
454 /* ARGSUSED */
455 int
456 fifo_advlock(void *v)
457 {
458 	return (EOPNOTSUPP);
459 }
460 
461 int
462 fifo_kqfilter(void *v)
463 {
464 	struct vop_kqfilter_args *ap = v;
465 	struct fifoinfo *fip = ap->a_vp->v_fifoinfo;
466 	struct sockbuf *sb;
467 	struct socket *so;
468 
469 	switch (ap->a_kn->kn_filter) {
470 	case EVFILT_READ:
471 		if (!(ap->a_fflag & FREAD))
472 			return (EINVAL);
473 		ap->a_kn->kn_fop = &fiforead_filtops;
474 		so = fip->fi_readsock;
475 		sb = &so->so_rcv;
476 		break;
477 	case EVFILT_WRITE:
478 		if (!(ap->a_fflag & FWRITE)) {
479 			/* Tell upper layer to ask for POLLUP only */
480 			if (ap->a_kn->kn_flags & (__EV_POLL | __EV_SELECT))
481 				return (EPERM);
482 			return (EINVAL);
483 		}
484 		ap->a_kn->kn_fop = &fifowrite_filtops;
485 		so = fip->fi_writesock;
486 		sb = &so->so_snd;
487 		break;
488 	case EVFILT_EXCEPT:
489 		if (ap->a_kn->kn_flags & __EV_SELECT) {
490 			/* Prevent triggering exceptfds. */
491 			return (EPERM);
492 		}
493 		if ((ap->a_kn->kn_flags & __EV_POLL) == 0) {
494 			/* Disallow usage through kevent(2). */
495 			return (EINVAL);
496 		}
497 		ap->a_kn->kn_fop = &fifoexcept_filtops;
498 		so = fip->fi_readsock;
499 		sb = &so->so_rcv;
500 		break;
501 	default:
502 		return (EINVAL);
503 	}
504 
505 	ap->a_kn->kn_hook = so;
506 
507 	klist_insert(&sb->sb_sel.si_note, ap->a_kn);
508 
509 	return (0);
510 }
511 
512 void
513 filt_fifordetach(struct knote *kn)
514 {
515 	struct socket *so = (struct socket *)kn->kn_hook;
516 
517 	klist_remove(&so->so_rcv.sb_sel.si_note, kn);
518 }
519 
520 int
521 filt_fiforead(struct knote *kn, long hint)
522 {
523 	struct socket *so = kn->kn_hook;
524 	int rv;
525 
526 	soassertlocked(so);
527 
528 	kn->kn_data = so->so_rcv.sb_cc;
529 	if (so->so_rcv.sb_state & SS_CANTRCVMORE) {
530 		kn->kn_flags |= EV_EOF;
531 		if (kn->kn_flags & __EV_POLL) {
532 			if (so->so_state & SS_ISDISCONNECTED)
533 				kn->kn_flags |= __EV_HUP;
534 			else
535 				kn->kn_flags &= ~__EV_HUP;
536 		}
537 		rv = 1;
538 	} else {
539 		kn->kn_flags &= ~(EV_EOF | __EV_HUP);
540 		rv = (kn->kn_data > 0);
541 	}
542 
543 	return (rv);
544 }
545 
546 void
547 filt_fifowdetach(struct knote *kn)
548 {
549 	struct socket *so = (struct socket *)kn->kn_hook;
550 
551 	klist_remove(&so->so_snd.sb_sel.si_note, kn);
552 }
553 
554 int
555 filt_fifowrite(struct knote *kn, long hint)
556 {
557 	struct socket *so = kn->kn_hook;
558 	int rv;
559 
560 	soassertlocked(so);
561 
562 	kn->kn_data = sbspace(so, &so->so_snd);
563 	if (so->so_snd.sb_state & SS_CANTSENDMORE) {
564 		kn->kn_flags |= EV_EOF;
565 		rv = 1;
566 	} else {
567 		kn->kn_flags &= ~EV_EOF;
568 		rv = (kn->kn_data >= so->so_snd.sb_lowat);
569 	}
570 
571 	return (rv);
572 }
573 
574 int
575 filt_fifoexcept(struct knote *kn, long hint)
576 {
577 	struct socket *so = kn->kn_hook;
578 	int rv = 0;
579 
580 	soassertlocked(so);
581 
582 	if (kn->kn_flags & __EV_POLL) {
583 		if (so->so_state & SS_ISDISCONNECTED) {
584 			kn->kn_flags |= __EV_HUP;
585 			rv = 1;
586 		} else {
587 			kn->kn_flags &= ~__EV_HUP;
588 		}
589 	}
590 
591 	return (rv);
592 }
593 
594 int
595 filt_fifomodify(struct kevent *kev, struct knote *kn)
596 {
597 	struct socket *so = kn->kn_hook;
598 	int rv;
599 
600 	solock(so);
601 	rv = knote_modify(kev, kn);
602 	sounlock(so);
603 
604 	return (rv);
605 }
606 
607 int
608 filt_fifoprocess(struct knote *kn, struct kevent *kev)
609 {
610 	struct socket *so = kn->kn_hook;
611 	int rv;
612 
613 	solock(so);
614 	rv = knote_process(kn, kev);
615 	sounlock(so);
616 
617 	return (rv);
618 }
619