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