fifo_vnops.c revision 1.30.4.1 1 /* $NetBSD: fifo_vnops.c,v 1.30.4.1 2001/07/10 14:00:00 lukem Exp $ */
2
3 /*
4 * Copyright (c) 1990, 1993, 1995
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)fifo_vnops.c 8.10 (Berkeley) 5/27/95
36 */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/proc.h>
41 #include <sys/time.h>
42 #include <sys/namei.h>
43 #include <sys/vnode.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/stat.h>
47 #include <sys/ioctl.h>
48 #include <sys/file.h>
49 #include <sys/errno.h>
50 #include <sys/malloc.h>
51 #include <sys/un.h>
52 #include <sys/poll.h>
53 #include <sys/event.h>
54
55 #include <miscfs/fifofs/fifo.h>
56 #include <miscfs/genfs/genfs.h>
57
58 /*
59 * This structure is associated with the FIFO vnode and stores
60 * the state associated with the FIFO.
61 */
62 struct fifoinfo {
63 struct socket *fi_readsock;
64 struct socket *fi_writesock;
65 long fi_readers;
66 long fi_writers;
67 };
68
69 static void filt_fifordetach(struct knote *kn);
70 static int filt_fiforead(struct knote *kn, long hint);
71 static void filt_fifowdetach(struct knote *kn);
72 static int filt_fifowrite(struct knote *kn, long hint);
73
74 struct filterops fiforead_filtops =
75 { 1, NULL, filt_fifordetach, filt_fiforead };
76 struct filterops fifowrite_filtops =
77 { 1, NULL, filt_fifowdetach, filt_fifowrite };
78
79 int (**fifo_vnodeop_p) __P((void *));
80 const struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
81 { &vop_default_desc, vn_default_error },
82 { &vop_lookup_desc, fifo_lookup }, /* lookup */
83 { &vop_create_desc, fifo_create }, /* create */
84 { &vop_mknod_desc, fifo_mknod }, /* mknod */
85 { &vop_open_desc, fifo_open }, /* open */
86 { &vop_close_desc, fifo_close }, /* close */
87 { &vop_access_desc, fifo_access }, /* access */
88 { &vop_getattr_desc, fifo_getattr }, /* getattr */
89 { &vop_setattr_desc, fifo_setattr }, /* setattr */
90 { &vop_read_desc, fifo_read }, /* read */
91 { &vop_write_desc, fifo_write }, /* write */
92 { &vop_lease_desc, fifo_lease_check }, /* lease */
93 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
94 { &vop_poll_desc, fifo_poll }, /* poll */
95 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */
96 { &vop_revoke_desc, fifo_revoke }, /* revoke */
97 { &vop_mmap_desc, fifo_mmap }, /* mmap */
98 { &vop_fsync_desc, fifo_fsync }, /* fsync */
99 { &vop_seek_desc, fifo_seek }, /* seek */
100 { &vop_remove_desc, fifo_remove }, /* remove */
101 { &vop_link_desc, fifo_link }, /* link */
102 { &vop_rename_desc, fifo_rename }, /* rename */
103 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
104 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
105 { &vop_symlink_desc, fifo_symlink }, /* symlink */
106 { &vop_readdir_desc, fifo_readdir }, /* readdir */
107 { &vop_readlink_desc, fifo_readlink }, /* readlink */
108 { &vop_abortop_desc, fifo_abortop }, /* abortop */
109 { &vop_inactive_desc, fifo_inactive }, /* inactive */
110 { &vop_reclaim_desc, fifo_reclaim }, /* reclaim */
111 { &vop_lock_desc, fifo_lock }, /* lock */
112 { &vop_unlock_desc, fifo_unlock }, /* unlock */
113 { &vop_bmap_desc, fifo_bmap }, /* bmap */
114 { &vop_strategy_desc, fifo_strategy }, /* strategy */
115 { &vop_print_desc, fifo_print }, /* print */
116 { &vop_islocked_desc, fifo_islocked }, /* islocked */
117 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
118 { &vop_advlock_desc, fifo_advlock }, /* advlock */
119 { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */
120 { &vop_valloc_desc, fifo_valloc }, /* valloc */
121 { &vop_vfree_desc, fifo_vfree }, /* vfree */
122 { &vop_truncate_desc, fifo_truncate }, /* truncate */
123 { &vop_update_desc, fifo_update }, /* update */
124 { &vop_bwrite_desc, fifo_bwrite }, /* bwrite */
125 { (struct vnodeop_desc*)NULL, (int(*) __P((void *)))NULL }
126 };
127 const struct vnodeopv_desc fifo_vnodeop_opv_desc =
128 { &fifo_vnodeop_p, fifo_vnodeop_entries };
129
130 /*
131 * Trivial lookup routine that always fails.
132 */
133 /* ARGSUSED */
134 int
135 fifo_lookup(void *v)
136 {
137 struct vop_lookup_args /* {
138 struct vnode *a_dvp;
139 struct vnode **a_vpp;
140 struct componentname *a_cnp;
141 } */ *ap = v;
142
143 *ap->a_vpp = NULL;
144 return (ENOTDIR);
145 }
146
147 /*
148 * Open called to set up a new instance of a fifo or
149 * to find an active instance of a fifo.
150 */
151 /* ARGSUSED */
152 int
153 fifo_open(void *v)
154 {
155 struct vop_open_args /* {
156 struct vnode *a_vp;
157 int a_mode;
158 struct ucred *a_cred;
159 struct proc *a_p;
160 } */ *ap = v;
161 struct vnode *vp;
162 struct fifoinfo *fip;
163 struct proc *p;
164 struct socket *rso, *wso;
165 int error;
166 static const char openstr[] = "fifo";
167
168 vp = ap->a_vp;
169 p = ap->a_p;
170
171 if ((fip = vp->v_fifoinfo) == NULL) {
172 MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK);
173 vp->v_fifoinfo = fip;
174 if ((error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0)) != 0) {
175 free(fip, M_VNODE);
176 vp->v_fifoinfo = NULL;
177 return (error);
178 }
179 fip->fi_readsock = rso;
180 if ((error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0)) != 0) {
181 (void)soclose(rso);
182 free(fip, M_VNODE);
183 vp->v_fifoinfo = NULL;
184 return (error);
185 }
186 fip->fi_writesock = wso;
187 if ((error = unp_connect2(wso, rso)) != 0) {
188 (void)soclose(wso);
189 (void)soclose(rso);
190 free(fip, M_VNODE);
191 vp->v_fifoinfo = NULL;
192 return (error);
193 }
194 fip->fi_readers = fip->fi_writers = 0;
195 wso->so_state |= SS_CANTRCVMORE;
196 rso->so_state |= SS_CANTSENDMORE;
197 }
198 if (ap->a_mode & FREAD) {
199 if (fip->fi_readers++ == 0) {
200 fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
201 if (fip->fi_writers > 0)
202 wakeup((caddr_t)&fip->fi_writers);
203 }
204 }
205 if (ap->a_mode & FWRITE) {
206 if (fip->fi_writers++ == 0) {
207 fip->fi_readsock->so_state &= ~SS_CANTRCVMORE;
208 if (fip->fi_readers > 0)
209 wakeup((caddr_t)&fip->fi_readers);
210 }
211 }
212 if (ap->a_mode & FREAD) {
213 if (ap->a_mode & O_NONBLOCK) {
214 } else {
215 while (fip->fi_writers == 0) {
216 VOP_UNLOCK(vp, 0);
217 error = tsleep((caddr_t)&fip->fi_readers,
218 PCATCH | PSOCK, openstr, 0);
219 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
220 if (error)
221 goto bad;
222 }
223 }
224 }
225 if (ap->a_mode & FWRITE) {
226 if (ap->a_mode & O_NONBLOCK) {
227 if (fip->fi_readers == 0) {
228 error = ENXIO;
229 goto bad;
230 }
231 } else {
232 while (fip->fi_readers == 0) {
233 VOP_UNLOCK(vp, 0);
234 error = tsleep((caddr_t)&fip->fi_writers,
235 PCATCH | PSOCK, openstr, 0);
236 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
237 if (error)
238 goto bad;
239 }
240 }
241 }
242 return (0);
243 bad:
244 VOP_CLOSE(vp, ap->a_mode, ap->a_cred, p);
245 return (error);
246 }
247
248 /*
249 * Vnode op for read
250 */
251 /* ARGSUSED */
252 int
253 fifo_read(void *v)
254 {
255 struct vop_read_args /* {
256 struct vnode *a_vp;
257 struct uio *a_uio;
258 int a_ioflag;
259 struct ucred *a_cred;
260 } */ *ap = v;
261 struct uio *uio;
262 struct socket *rso;
263 int error, startresid;
264
265 uio = ap->a_uio;
266 rso = ap->a_vp->v_fifoinfo->fi_readsock;
267 #ifdef DIAGNOSTIC
268 if (uio->uio_rw != UIO_READ)
269 panic("fifo_read mode");
270 #endif
271 if (uio->uio_resid == 0)
272 return (0);
273 if (ap->a_ioflag & IO_NDELAY)
274 rso->so_state |= SS_NBIO;
275 startresid = uio->uio_resid;
276 VOP_UNLOCK(ap->a_vp, 0);
277 error = (*rso->so_receive)(rso, (struct mbuf **)0, uio,
278 (struct mbuf **)0, (struct mbuf **)0, (int *)0);
279 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
280 /*
281 * Clear EOF indication after first such return.
282 */
283 if (uio->uio_resid == startresid)
284 rso->so_state &= ~SS_CANTRCVMORE;
285 if (ap->a_ioflag & IO_NDELAY) {
286 rso->so_state &= ~SS_NBIO;
287 if (error == EWOULDBLOCK &&
288 ap->a_vp->v_fifoinfo->fi_writers == 0)
289 error = 0;
290 }
291 return (error);
292 }
293
294 /*
295 * Vnode op for write
296 */
297 /* ARGSUSED */
298 int
299 fifo_write(void *v)
300 {
301 struct vop_write_args /* {
302 struct vnode *a_vp;
303 struct uio *a_uio;
304 int a_ioflag;
305 struct ucred *a_cred;
306 } */ *ap = v;
307 struct socket *wso;
308 int error;
309
310 wso = ap->a_vp->v_fifoinfo->fi_writesock;
311 #ifdef DIAGNOSTIC
312 if (ap->a_uio->uio_rw != UIO_WRITE)
313 panic("fifo_write mode");
314 #endif
315 if (ap->a_ioflag & IO_NDELAY)
316 wso->so_state |= SS_NBIO;
317 VOP_UNLOCK(ap->a_vp, 0);
318 error = (*wso->so_send)(wso, (struct mbuf *)0, ap->a_uio, 0,
319 (struct mbuf *)0, 0);
320 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
321 if (ap->a_ioflag & IO_NDELAY)
322 wso->so_state &= ~SS_NBIO;
323 return (error);
324 }
325
326 /*
327 * Device ioctl operation.
328 */
329 /* ARGSUSED */
330 int
331 fifo_ioctl(void *v)
332 {
333 struct vop_ioctl_args /* {
334 struct vnode *a_vp;
335 u_long a_command;
336 caddr_t a_data;
337 int a_fflag;
338 struct ucred *a_cred;
339 struct proc *a_p;
340 } */ *ap = v;
341 struct file filetmp;
342 int error;
343
344 if (ap->a_command == FIONBIO)
345 return (0);
346 if (ap->a_fflag & FREAD) {
347 filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
348 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
349 if (error)
350 return (error);
351 }
352 if (ap->a_fflag & FWRITE) {
353 filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
354 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
355 if (error)
356 return (error);
357 }
358 return (0);
359 }
360
361 /* ARGSUSED */
362 int
363 fifo_poll(void *v)
364 {
365 struct vop_poll_args /* {
366 struct vnode *a_vp;
367 int a_events;
368 struct proc *a_p;
369 } */ *ap = v;
370 struct file filetmp;
371 int revents;
372
373 revents = 0;
374 if (ap->a_events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
375 filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
376 if (filetmp.f_data)
377 revents |= soo_poll(&filetmp, ap->a_events, ap->a_p);
378 }
379 if (ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
380 filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
381 if (filetmp.f_data)
382 revents |= soo_poll(&filetmp, ap->a_events, ap->a_p);
383 }
384
385 return (revents);
386 }
387
388 int
389 fifo_inactive(void *v)
390 {
391 struct vop_inactive_args /* {
392 struct vnode *a_vp;
393 struct proc *a_p;
394 } */ *ap = v;
395
396 VOP_UNLOCK(ap->a_vp, 0);
397 return (0);
398 }
399
400 /*
401 * This is a noop, simply returning what one has been given.
402 */
403 int
404 fifo_bmap(void *v)
405 {
406 struct vop_bmap_args /* {
407 struct vnode *a_vp;
408 daddr_t a_bn;
409 struct vnode **a_vpp;
410 daddr_t *a_bnp;
411 int *a_runp;
412 } */ *ap = v;
413
414 if (ap->a_vpp != NULL)
415 *ap->a_vpp = ap->a_vp;
416 if (ap->a_bnp != NULL)
417 *ap->a_bnp = ap->a_bn;
418 if (ap->a_runp != NULL)
419 *ap->a_runp = 0;
420 return (0);
421 }
422
423 /*
424 * Device close routine
425 */
426 /* ARGSUSED */
427 int
428 fifo_close(void *v)
429 {
430 struct vop_close_args /* {
431 struct vnode *a_vp;
432 int a_fflag;
433 struct ucred *a_cred;
434 struct proc *a_p;
435 } */ *ap = v;
436 struct vnode *vp;
437 struct fifoinfo *fip;
438 int error1, error2;
439
440 vp = ap->a_vp;
441 fip = vp->v_fifoinfo;
442 if (ap->a_fflag & FREAD) {
443 if (--fip->fi_readers == 0)
444 socantsendmore(fip->fi_writesock);
445 }
446 if (ap->a_fflag & FWRITE) {
447 if (--fip->fi_writers == 0)
448 socantrcvmore(fip->fi_readsock);
449 }
450 if (vp->v_usecount > 1)
451 return (0);
452 error1 = soclose(fip->fi_readsock);
453 error2 = soclose(fip->fi_writesock);
454 FREE(fip, M_VNODE);
455 vp->v_fifoinfo = NULL;
456 if (error1)
457 return (error1);
458 return (error2);
459 }
460
461 /*
462 * Print out the contents of a fifo vnode.
463 */
464 int
465 fifo_print(void *v)
466 {
467 struct vop_print_args /* {
468 struct vnode *a_vp;
469 } */ *ap = v;
470
471 printf("tag VT_NON");
472 fifo_printinfo(ap->a_vp);
473 printf("\n");
474 return 0;
475 }
476
477 /*
478 * Print out internal contents of a fifo vnode.
479 */
480 void
481 fifo_printinfo(struct vnode *vp)
482 {
483 struct fifoinfo *fip;
484
485 fip = vp->v_fifoinfo;
486 printf(", fifo with %ld readers and %ld writers",
487 fip->fi_readers, fip->fi_writers);
488 }
489
490 /*
491 * Return POSIX pathconf information applicable to fifo's.
492 */
493 int
494 fifo_pathconf(void *v)
495 {
496 struct vop_pathconf_args /* {
497 struct vnode *a_vp;
498 int a_name;
499 register_t *a_retval;
500 } */ *ap = v;
501
502 switch (ap->a_name) {
503 case _PC_LINK_MAX:
504 *ap->a_retval = LINK_MAX;
505 return (0);
506 case _PC_PIPE_BUF:
507 *ap->a_retval = PIPE_BUF;
508 return (0);
509 case _PC_CHOWN_RESTRICTED:
510 *ap->a_retval = 1;
511 return (0);
512 case _PC_SYNC_IO:
513 *ap->a_retval = 1;
514 return (0);
515 default:
516 return (EINVAL);
517 }
518 /* NOTREACHED */
519 }
520
521 /* ARGSUSED */
522 int
523 fifo_kqfilter(void *v)
524 {
525 struct vop_kqfilter_args /* {
526 struct vnode *a_vp;
527 struct knote *a_kn;
528 } */ *ap = v;
529 struct socket *so;
530 struct sockbuf *sb;
531
532 so = (struct socket *)ap->a_vp->v_fifoinfo->fi_readsock;
533 switch (ap->a_kn->kn_filter) {
534 case EVFILT_READ:
535 ap->a_kn->kn_fop = &fiforead_filtops;
536 sb = &so->so_rcv;
537 break;
538 case EVFILT_WRITE:
539 ap->a_kn->kn_fop = &fifowrite_filtops;
540 sb = &so->so_snd;
541 break;
542 default:
543 return (1);
544 }
545
546 SLIST_INSERT_HEAD(&sb->sb_sel.si_klist, ap->a_kn, kn_selnext);
547 sb->sb_flags |= SB_KNOTE;
548 return (0);
549 }
550
551 static void
552 filt_fifordetach(struct knote *kn)
553 {
554 struct socket *so;
555
556 so = (struct socket *)kn->kn_hook;
557 SLIST_REMOVE(&so->so_rcv.sb_sel.si_klist, kn, knote, kn_selnext);
558 if (SLIST_EMPTY(&so->so_rcv.sb_sel.si_klist))
559 so->so_rcv.sb_flags &= ~SB_KNOTE;
560 }
561
562 static int
563 filt_fiforead(struct knote *kn, long hint)
564 {
565 struct socket *so;
566
567 so = (struct socket *)kn->kn_hook;
568 kn->kn_data = so->so_rcv.sb_cc;
569 if (so->so_state & SS_CANTRCVMORE) {
570 kn->kn_flags |= EV_EOF;
571 return (1);
572 }
573 kn->kn_flags &= ~EV_EOF;
574 return (kn->kn_data > 0);
575 }
576
577 static void
578 filt_fifowdetach(struct knote *kn)
579 {
580 struct socket *so;
581
582 so = (struct socket *)kn->kn_hook;
583 SLIST_REMOVE(&so->so_snd.sb_sel.si_klist, kn, knote, kn_selnext);
584 if (SLIST_EMPTY(&so->so_snd.sb_sel.si_klist))
585 so->so_snd.sb_flags &= ~SB_KNOTE;
586 }
587
588 static int
589 filt_fifowrite(struct knote *kn, long hint)
590 {
591 struct socket *so;
592
593 so = (struct socket *)kn->kn_hook;
594 kn->kn_data = sbspace(&so->so_snd);
595 if (so->so_state & SS_CANTSENDMORE) {
596 kn->kn_flags |= EV_EOF;
597 return (1);
598 }
599 kn->kn_flags &= ~EV_EOF;
600 return (kn->kn_data >= so->so_snd.sb_lowat);
601 }
602