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