1 /* $OpenBSD: fifo_vnops.c,v 1.101 2023/01/27 18:46:34 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_klist, 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_klist, 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_klist, 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 }
Cache object: 56edcf245d4c802b69b57d1605dd64b5
|