1 /* $NetBSD: fifo_vnops.c,v 1.65 2008/04/24 15:18:11 ad Exp $ */
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
30 * Copyright (c) 1990, 1993, 1995
31 * The Regents of the University of California. All rights reserved.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * @(#)fifo_vnops.c 8.10 (Berkeley) 5/27/95
60 #include <sys/cdefs.h>
61 __KERNEL_RCSID(0, "$NetBSD: fifo_vnops.c,v 1.65 2008/04/24 15:18:11 ad Exp $");
63 #include <sys/param.h>
64 #include <sys/systm.h>
67 #include <sys/namei.h>
68 #include <sys/vnode.h>
69 #include <sys/socket.h>
70 #include <sys/protosw.h>
71 #include <sys/socketvar.h>
73 #include <sys/ioctl.h>
75 #include <sys/errno.h>
79 #include <sys/event.h>
80 #include <sys/condvar.h>
82 #include <miscfs/fifofs/fifo.h>
83 #include <miscfs/genfs/genfs.h>
86 * This structure is associated with the FIFO vnode and stores
87 * the state associated with the FIFO.
90 struct socket
*fi_readsock
;
91 struct socket
*fi_writesock
;
98 int (**fifo_vnodeop_p
)(void *);
99 const struct vnodeopv_entry_desc fifo_vnodeop_entries
[] = {
100 { &vop_default_desc
, vn_default_error
},
101 { &vop_lookup_desc
, fifo_lookup
}, /* lookup */
102 { &vop_create_desc
, fifo_create
}, /* create */
103 { &vop_mknod_desc
, fifo_mknod
}, /* mknod */
104 { &vop_open_desc
, fifo_open
}, /* open */
105 { &vop_close_desc
, fifo_close
}, /* close */
106 { &vop_access_desc
, fifo_access
}, /* access */
107 { &vop_getattr_desc
, fifo_getattr
}, /* getattr */
108 { &vop_setattr_desc
, fifo_setattr
}, /* setattr */
109 { &vop_read_desc
, fifo_read
}, /* read */
110 { &vop_write_desc
, fifo_write
}, /* write */
111 { &vop_ioctl_desc
, fifo_ioctl
}, /* ioctl */
112 { &vop_poll_desc
, fifo_poll
}, /* poll */
113 { &vop_kqfilter_desc
, fifo_kqfilter
}, /* kqfilter */
114 { &vop_revoke_desc
, fifo_revoke
}, /* revoke */
115 { &vop_mmap_desc
, fifo_mmap
}, /* mmap */
116 { &vop_fsync_desc
, fifo_fsync
}, /* fsync */
117 { &vop_seek_desc
, fifo_seek
}, /* seek */
118 { &vop_remove_desc
, fifo_remove
}, /* remove */
119 { &vop_link_desc
, fifo_link
}, /* link */
120 { &vop_rename_desc
, fifo_rename
}, /* rename */
121 { &vop_mkdir_desc
, fifo_mkdir
}, /* mkdir */
122 { &vop_rmdir_desc
, fifo_rmdir
}, /* rmdir */
123 { &vop_symlink_desc
, fifo_symlink
}, /* symlink */
124 { &vop_readdir_desc
, fifo_readdir
}, /* readdir */
125 { &vop_readlink_desc
, fifo_readlink
}, /* readlink */
126 { &vop_abortop_desc
, fifo_abortop
}, /* abortop */
127 { &vop_inactive_desc
, fifo_inactive
}, /* inactive */
128 { &vop_reclaim_desc
, fifo_reclaim
}, /* reclaim */
129 { &vop_lock_desc
, fifo_lock
}, /* lock */
130 { &vop_unlock_desc
, fifo_unlock
}, /* unlock */
131 { &vop_bmap_desc
, fifo_bmap
}, /* bmap */
132 { &vop_strategy_desc
, fifo_strategy
}, /* strategy */
133 { &vop_print_desc
, fifo_print
}, /* print */
134 { &vop_islocked_desc
, fifo_islocked
}, /* islocked */
135 { &vop_pathconf_desc
, fifo_pathconf
}, /* pathconf */
136 { &vop_advlock_desc
, fifo_advlock
}, /* advlock */
137 { &vop_bwrite_desc
, fifo_bwrite
}, /* bwrite */
138 { &vop_putpages_desc
, fifo_putpages
}, /* putpages */
139 { (struct vnodeop_desc
*)NULL
, (int(*)(void *))NULL
}
141 const struct vnodeopv_desc fifo_vnodeop_opv_desc
=
142 { &fifo_vnodeop_p
, fifo_vnodeop_entries
};
145 * Trivial lookup routine that always fails.
151 struct vop_lookup_args
/* {
153 struct vnode **a_vpp;
154 struct componentname *a_cnp;
162 * Open called to set up a new instance of a fifo or
163 * to find an active instance of a fifo.
169 struct vop_open_args
/* {
174 struct lwp
*l
= curlwp
;
176 struct fifoinfo
*fip
;
178 struct socket
*rso
, *wso
;
184 if ((fip
= vp
->v_fifoinfo
) == NULL
) {
185 fip
= kmem_alloc(sizeof(*fip
), KM_SLEEP
);
186 vp
->v_fifoinfo
= fip
;
187 error
= socreate(AF_LOCAL
, &rso
, SOCK_STREAM
, 0, l
, NULL
);
189 kmem_free(fip
, sizeof(*fip
));
190 vp
->v_fifoinfo
= NULL
;
193 fip
->fi_readsock
= rso
;
194 error
= socreate(AF_LOCAL
, &wso
, SOCK_STREAM
, 0, l
, rso
);
197 kmem_free(fip
, sizeof(*fip
));
198 vp
->v_fifoinfo
= NULL
;
201 fip
->fi_writesock
= wso
;
203 if ((error
= unp_connect2(wso
, rso
, PRU_CONNECT2
)) != 0) {
207 kmem_free(fip
, sizeof(*fip
));
208 vp
->v_fifoinfo
= NULL
;
213 wso
->so_state
|= SS_CANTRCVMORE
;
214 rso
->so_state
|= SS_CANTSENDMORE
;
215 cv_init(&fip
->fi_rcv
, "fiford");
216 cv_init(&fip
->fi_wcv
, "fifowr");
218 wso
= fip
->fi_writesock
;
219 rso
= fip
->fi_readsock
;
223 if (ap
->a_mode
& FREAD
) {
224 if (fip
->fi_readers
++ == 0) {
225 wso
->so_state
&= ~SS_CANTSENDMORE
;
226 cv_broadcast(&fip
->fi_wcv
);
229 if (ap
->a_mode
& FWRITE
) {
230 if (fip
->fi_writers
++ == 0) {
231 rso
->so_state
&= ~SS_CANTRCVMORE
;
232 cv_broadcast(&fip
->fi_rcv
);
235 if (ap
->a_mode
& FREAD
) {
236 if (ap
->a_mode
& O_NONBLOCK
) {
238 while (!soreadable(rso
) && fip
->fi_writers
== 0) {
240 error
= cv_wait_sig(&fip
->fi_rcv
,
243 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
250 if (ap
->a_mode
& FWRITE
) {
251 if (ap
->a_mode
& O_NONBLOCK
) {
252 if (fip
->fi_readers
== 0) {
258 while (fip
->fi_readers
== 0) {
260 error
= cv_wait_sig(&fip
->fi_wcv
,
263 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
273 VOP_CLOSE(vp
, ap
->a_mode
, ap
->a_cred
);
284 struct vop_read_args
/* {
296 rso
= ap
->a_vp
->v_fifoinfo
->fi_readsock
;
298 if (uio
->uio_rw
!= UIO_READ
)
299 panic("fifo_read mode");
301 if (uio
->uio_resid
== 0)
303 startresid
= uio
->uio_resid
;
304 VOP_UNLOCK(ap
->a_vp
, 0);
305 if (ap
->a_ioflag
& IO_NDELAY
) {
306 /* XXX Bogus, affects other threads. */
309 error
= (*rso
->so_receive
)(rso
, NULL
, uio
, NULL
, NULL
, NULL
);
311 * Clear EOF indication after first such return.
313 if (uio
->uio_resid
== startresid
)
314 rso
->so_state
&= ~SS_CANTRCVMORE
;
315 if (ap
->a_ioflag
& IO_NDELAY
) {
317 if (error
== EWOULDBLOCK
&&
318 ap
->a_vp
->v_fifoinfo
->fi_writers
== 0)
321 vn_lock(ap
->a_vp
, LK_EXCLUSIVE
| LK_RETRY
);
332 struct vop_write_args
/* {
341 wso
= ap
->a_vp
->v_fifoinfo
->fi_writesock
;
343 if (ap
->a_uio
->uio_rw
!= UIO_WRITE
)
344 panic("fifo_write mode");
346 VOP_UNLOCK(ap
->a_vp
, 0);
347 if (ap
->a_ioflag
& IO_NDELAY
) {
348 /* XXX Bogus, affects other threads. */
351 error
= (*wso
->so_send
)(wso
, NULL
, ap
->a_uio
, 0, NULL
, 0, curlwp
);
352 if (ap
->a_ioflag
& IO_NDELAY
)
354 vn_lock(ap
->a_vp
, LK_EXCLUSIVE
| LK_RETRY
);
359 * Device ioctl operation.
365 struct vop_ioctl_args
/* {
376 if (ap
->a_command
== FIONBIO
)
378 if (ap
->a_fflag
& FREAD
) {
379 filetmp
.f_data
= ap
->a_vp
->v_fifoinfo
->fi_readsock
;
380 error
= soo_ioctl(&filetmp
, ap
->a_command
, ap
->a_data
);
384 if (ap
->a_fflag
& FWRITE
) {
385 filetmp
.f_data
= ap
->a_vp
->v_fifoinfo
->fi_writesock
;
386 error
= soo_ioctl(&filetmp
, ap
->a_command
, ap
->a_data
);
397 struct vop_poll_args
/* {
406 if (ap
->a_events
& (POLLIN
| POLLPRI
| POLLRDNORM
| POLLRDBAND
)) {
407 so
= ap
->a_vp
->v_fifoinfo
->fi_readsock
;
409 revents
|= sopoll(so
, ap
->a_events
);
411 if (ap
->a_events
& (POLLOUT
| POLLWRNORM
| POLLWRBAND
)) {
412 so
= ap
->a_vp
->v_fifoinfo
->fi_writesock
;
414 revents
|= sopoll(so
, ap
->a_events
);
421 fifo_inactive(void *v
)
423 struct vop_inactive_args
/* {
428 VOP_UNLOCK(ap
->a_vp
, 0);
433 * This is a noop, simply returning what one has been given.
438 struct vop_bmap_args
/* {
441 struct vnode **a_vpp;
446 if (ap
->a_vpp
!= NULL
)
447 *ap
->a_vpp
= ap
->a_vp
;
448 if (ap
->a_bnp
!= NULL
)
449 *ap
->a_bnp
= ap
->a_bn
;
450 if (ap
->a_runp
!= NULL
)
456 * Device close routine
462 struct vop_close_args
/* {
469 struct fifoinfo
*fip
;
470 struct socket
*wso
, *rso
;
474 fip
= vp
->v_fifoinfo
;
475 isrevoke
= (ap
->a_fflag
& (FREAD
| FWRITE
| FNONBLOCK
)) == FNONBLOCK
;
476 wso
= fip
->fi_writesock
;
477 rso
= fip
->fi_readsock
;
480 if (fip
->fi_readers
!= 0) {
484 if (fip
->fi_writers
!= 0) {
489 if ((ap
->a_fflag
& FREAD
) && --fip
->fi_readers
== 0)
491 if ((ap
->a_fflag
& FWRITE
) && --fip
->fi_writers
== 0)
494 if ((fip
->fi_readers
+ fip
->fi_writers
) == 0) {
498 cv_destroy(&fip
->fi_rcv
);
499 cv_destroy(&fip
->fi_wcv
);
500 kmem_free(fip
, sizeof(*fip
));
501 vp
->v_fifoinfo
= NULL
;
508 * Print out the contents of a fifo vnode.
513 struct vop_print_args
/* {
517 printf("tag VT_NON");
518 fifo_printinfo(ap
->a_vp
);
524 * Print out internal contents of a fifo vnode.
527 fifo_printinfo(struct vnode
*vp
)
529 struct fifoinfo
*fip
;
531 fip
= vp
->v_fifoinfo
;
532 printf(", fifo with %d readers and %d writers",
533 fip
->fi_readers
, fip
->fi_writers
);
537 * Return POSIX pathconf information applicable to fifo's.
540 fifo_pathconf(void *v
)
542 struct vop_pathconf_args
/* {
545 register_t *a_retval;
548 switch (ap
->a_name
) {
550 *ap
->a_retval
= LINK_MAX
;
553 *ap
->a_retval
= PIPE_BUF
;
555 case _PC_CHOWN_RESTRICTED
:
568 filt_fifordetach(struct knote
*kn
)
572 so
= (struct socket
*)kn
->kn_hook
;
574 SLIST_REMOVE(&so
->so_rcv
.sb_sel
.sel_klist
, kn
, knote
, kn_selnext
);
575 if (SLIST_EMPTY(&so
->so_rcv
.sb_sel
.sel_klist
))
576 so
->so_rcv
.sb_flags
&= ~SB_KNOTE
;
581 filt_fiforead(struct knote
*kn
, long hint
)
586 so
= (struct socket
*)kn
->kn_hook
;
587 if (hint
!= NOTE_SUBMIT
)
589 kn
->kn_data
= so
->so_rcv
.sb_cc
;
590 if (so
->so_state
& SS_CANTRCVMORE
) {
591 kn
->kn_flags
|= EV_EOF
;
594 kn
->kn_flags
&= ~EV_EOF
;
595 rv
= (kn
->kn_data
> 0);
597 if (hint
!= NOTE_SUBMIT
)
603 filt_fifowdetach(struct knote
*kn
)
607 so
= (struct socket
*)kn
->kn_hook
;
609 SLIST_REMOVE(&so
->so_snd
.sb_sel
.sel_klist
, kn
, knote
, kn_selnext
);
610 if (SLIST_EMPTY(&so
->so_snd
.sb_sel
.sel_klist
))
611 so
->so_snd
.sb_flags
&= ~SB_KNOTE
;
616 filt_fifowrite(struct knote
*kn
, long hint
)
621 so
= (struct socket
*)kn
->kn_hook
;
622 if (hint
!= NOTE_SUBMIT
)
624 kn
->kn_data
= sbspace(&so
->so_snd
);
625 if (so
->so_state
& SS_CANTSENDMORE
) {
626 kn
->kn_flags
|= EV_EOF
;
629 kn
->kn_flags
&= ~EV_EOF
;
630 rv
= (kn
->kn_data
>= so
->so_snd
.sb_lowat
);
632 if (hint
!= NOTE_SUBMIT
)
637 static const struct filterops fiforead_filtops
=
638 { 1, NULL
, filt_fifordetach
, filt_fiforead
};
639 static const struct filterops fifowrite_filtops
=
640 { 1, NULL
, filt_fifowdetach
, filt_fifowrite
};
644 fifo_kqfilter(void *v
)
646 struct vop_kqfilter_args
/* {
653 so
= (struct socket
*)ap
->a_vp
->v_fifoinfo
->fi_readsock
;
654 switch (ap
->a_kn
->kn_filter
) {
656 ap
->a_kn
->kn_fop
= &fiforead_filtops
;
660 ap
->a_kn
->kn_fop
= &fifowrite_filtops
;
667 ap
->a_kn
->kn_hook
= so
;
670 SLIST_INSERT_HEAD(&sb
->sb_sel
.sel_klist
, ap
->a_kn
, kn_selnext
);
671 sb
->sb_flags
|= SB_KNOTE
;