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