diff options
author | phk <phk@FreeBSD.org> | 2004-11-15 14:51:44 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2004-11-15 14:51:44 +0000 |
commit | 0e1bc6bd7d8477826d2acd2c9387c6627a17300e (patch) | |
tree | b16c101b512c340906bb190fd0e737a688429f77 /sys/fs/fifofs | |
parent | acd420a745aab0d1fa41657549c99edf66d3f65a (diff) | |
download | FreeBSD-src-0e1bc6bd7d8477826d2acd2c9387c6627a17300e.zip FreeBSD-src-0e1bc6bd7d8477826d2acd2c9387c6627a17300e.tar.gz |
Add file ops to fifofs so that we can bypass vnodes (and Giant) for the
heavy-duty operations (read, write, poll/select, kqueue).
Disabled for now, enable with "vfs.fifofs.fops=1" in loader.conf.
Diffstat (limited to 'sys/fs/fifofs')
-rw-r--r-- | sys/fs/fifofs/fifo_vnops.c | 165 |
1 files changed, 164 insertions, 1 deletions
diff --git a/sys/fs/fifofs/fifo_vnops.c b/sys/fs/fifofs/fifo_vnops.c index d8e083f..af3664a 100644 --- a/sys/fs/fifofs/fifo_vnops.c +++ b/sys/fs/fifofs/fifo_vnops.c @@ -32,9 +32,10 @@ #include <sys/param.h> #include <sys/event.h> +#include <sys/file.h> +#include <sys/filedesc.h> #include <sys/filio.h> #include <sys/fcntl.h> -#include <sys/file.h> #include <sys/kernel.h> #include <sys/lock.h> #include <sys/mutex.h> @@ -51,6 +52,25 @@ #include <sys/vnode.h> #include <fs/fifofs/fifo.h> +static fo_rdwr_t fifo_read_f; +static fo_rdwr_t fifo_write_f; +static fo_ioctl_t fifo_ioctl_f; +static fo_poll_t fifo_poll_f; +static fo_kqfilter_t fifo_kqfilter_f; +static fo_stat_t fifo_stat_f; +static fo_close_t fifo_close_f; + +struct fileops fifo_ops_f = { + .fo_read = fifo_read_f, + .fo_write = fifo_write_f, + .fo_ioctl = fifo_ioctl_f, + .fo_poll = fifo_poll_f, + .fo_kqfilter = fifo_kqfilter_f, + .fo_stat = fifo_stat_f, + .fo_close = fifo_close_f, + .fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE +}; + /* * This structure is associated with the FIFO vnode and stores * the state associated with the FIFO. @@ -168,7 +188,16 @@ fifo_open(ap) struct thread *td = ap->a_td; struct ucred *cred = ap->a_cred; struct socket *rso, *wso; + struct file *fp; int error; + static int once, fifofs_fops; + + if (!once) { + TUNABLE_INT_FETCH("vfs.fifofs.fops", &fifofs_fops); + if (fifofs_fops) + printf("WARNING: FIFOFS uses fops\n"); + once = 1; + } if ((fip = vp->v_fifoinfo) == NULL) { MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK); @@ -279,6 +308,11 @@ fail1: } } mtx_unlock(&fifo_mtx); + fp = ap->a_td->td_proc->p_fd->fd_ofiles[ap->a_fdidx]; + if (fifofs_fops && fp->f_ops == &badfileops) { + fp->f_ops = &fifo_ops_f; + fp->f_data = fip; + } return (0); } @@ -648,3 +682,132 @@ fifo_advlock(ap) return (ap->a_flags & F_FLOCK ? EOPNOTSUPP : EINVAL); } + +static int +fifo_close_f(struct file *fp, struct thread *td) +{ + + return (vnops.fo_close(fp, td)); +} + +static int +fifo_ioctl_f(struct file *fp, u_long com, void *data, struct ucred *cred, struct thread *td) +{ + + return (vnops.fo_ioctl(fp, com, data, cred, td)); +} + +static int +fifo_kqfilter_f(struct file *fp, struct knote *kn) +{ + struct fifoinfo *fi; + struct socket *so; + struct sockbuf *sb; + + fi = fp->f_data; + switch (kn->kn_filter) { + case EVFILT_READ: + kn->kn_fop = &fiforead_filtops; + so = fi->fi_readsock; + sb = &so->so_rcv; + break; + case EVFILT_WRITE: + kn->kn_fop = &fifowrite_filtops; + so = fi->fi_writesock; + sb = &so->so_snd; + break; + default: + return (1); + } + + kn->kn_hook = (caddr_t)so; + + SOCKBUF_LOCK(sb); + knlist_add(&sb->sb_sel.si_note, kn, 1); + sb->sb_flags |= SB_KNOTE; + SOCKBUF_UNLOCK(sb); + + return (0); +} + +static int +fifo_poll_f(struct file *fp, int events, struct ucred *cred, struct thread *td) +{ + struct fifoinfo *fip; + struct file filetmp; + int levents, revents = 0; + + fip = fp->f_data; + levents = events & + (POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM | POLLRDBAND); + if (levents) { + /* + * If POLLIN or POLLRDNORM is requested and POLLINIGNEOF is + * not, then convert the first two to the last one. This + * tells the socket poll function to ignore EOF so that we + * block if there is no writer (and no data). Callers can + * set POLLINIGNEOF to get non-blocking behavior. + */ + if (levents & (POLLIN | POLLRDNORM) && + !(levents & POLLINIGNEOF)) { + levents &= ~(POLLIN | POLLRDNORM); + levents |= POLLINIGNEOF; + } + + filetmp.f_data = fip->fi_readsock; + filetmp.f_cred = cred; + if (filetmp.f_data) + revents |= soo_poll(&filetmp, levents, cred, td); + + /* Reverse the above conversion. */ + if ((revents & POLLINIGNEOF) && !(events & POLLINIGNEOF)) { + revents |= (events & (POLLIN | POLLRDNORM)); + revents &= ~POLLINIGNEOF; + } + } + levents = events & (POLLOUT | POLLWRNORM | POLLWRBAND); + if (events) { + filetmp.f_data = fip->fi_writesock; + filetmp.f_cred = cred; + if (filetmp.f_data) { + revents |= soo_poll(&filetmp, events, cred, td); + } + } + return (revents); +} + +static int +fifo_read_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td) +{ + struct fifoinfo *fip; + int error, sflags; + + fip = fp->f_data; + KASSERT(uio->uio_rw == UIO_READ,("fifo_read mode")); + if (uio->uio_resid == 0) + return (0); + sflags = (fp->f_flag & FNONBLOCK) ? MSG_NBIO : 0; + error = soreceive(fip->fi_readsock, NULL, uio, NULL, NULL, &sflags); + return (error); +} + +static int +fifo_stat_f(struct file *fp, struct stat *sb, struct ucred *cred, struct thread *td) +{ + + return (vnops.fo_stat(fp, sb, cred, td)); +} + +static int +fifo_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td) +{ + struct fifoinfo *fip; + int error, sflags; + + fip = fp->f_data; + KASSERT(uio->uio_rw == UIO_WRITE,("fifo_write mode")); + sflags = (fp->f_flag & FNONBLOCK) ? MSG_NBIO : 0; + error = sosend(fip->fi_writesock, NULL, uio, 0, NULL, sflags, td); + return (error); +} + |