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