diff --git a/sys/dev/cy/cy.c b/sys/dev/cy/cy.c index 9a56e2df1010..7d7671d9419b 100644 --- a/sys/dev/cy/cy.c +++ b/sys/dev/cy/cy.c @@ -405,8 +405,9 @@ static struct cdevsw sio_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; static int comconsole = -1; diff --git a/sys/dev/cy/cy_isa.c b/sys/dev/cy/cy_isa.c index 9a56e2df1010..7d7671d9419b 100644 --- a/sys/dev/cy/cy_isa.c +++ b/sys/dev/cy/cy_isa.c @@ -405,8 +405,9 @@ static struct cdevsw sio_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; static int comconsole = -1; diff --git a/sys/dev/dgb/dgb.c b/sys/dev/dgb/dgb.c index 84e81022c1f0..818aad7a8bbd 100644 --- a/sys/dev/dgb/dgb.c +++ b/sys/dev/dgb/dgb.c @@ -255,8 +255,9 @@ static struct cdevsw dgb_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; static speed_t dgbdefaultrate = TTYDEF_SPEED; diff --git a/sys/dev/dgb/dgm.c b/sys/dev/dgb/dgm.c index e6eef8f547ec..0e0bcfed9907 100644 --- a/sys/dev/dgb/dgm.c +++ b/sys/dev/dgb/dgm.c @@ -258,8 +258,9 @@ static struct cdevsw dgm_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; static speed_t dgmdefaultrate = TTYDEF_SPEED; diff --git a/sys/dev/rc/rc.c b/sys/dev/rc/rc.c index a7e5ecbc8d43..6c1ca5d4aaca 100644 --- a/sys/dev/rc/rc.c +++ b/sys/dev/rc/rc.c @@ -107,8 +107,9 @@ static struct cdevsw rc_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; /* Per-board structure */ diff --git a/sys/dev/si/si.c b/sys/dev/si/si.c index cc61a175111b..753849bf496c 100644 --- a/sys/dev/si/si.c +++ b/sys/dev/si/si.c @@ -129,8 +129,9 @@ static struct cdevsw si_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; static int si_Nports; diff --git a/sys/dev/sio/sio.c b/sys/dev/sio/sio.c index ee3d4f180cf6..d8f02c9b5cee 100644 --- a/sys/dev/sio/sio.c +++ b/sys/dev/sio/sio.c @@ -388,8 +388,9 @@ static struct cdevsw sio_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; int comconsole = -1; diff --git a/sys/dev/streams/streams.c b/sys/dev/streams/streams.c index 1d779f4a9f34..8f279da0cf1b 100644 --- a/sys/dev/streams/streams.c +++ b/sys/dev/streams/streams.c @@ -99,7 +99,8 @@ dev_t dt_ptm, dt_arp, dt_icmp, dt_ip, dt_tcp, dt_udp, dt_rawip, dt_unix_dgram, dt_unix_stream, dt_unix_ord_stream; static struct fileops svr4_netops = { - soo_read, soo_write, soo_ioctl, soo_poll, soo_stat, svr4_soo_close + soo_read, soo_write, soo_ioctl, soo_poll, sokqfilter, + soo_stat, svr4_soo_close }; #define CDEV_MAJOR 103 diff --git a/sys/dev/usb/umodem.c b/sys/dev/usb/umodem.c index 3305eeeb7172..b715c5ee0590 100644 --- a/sys/dev/usb/umodem.c +++ b/sys/dev/usb/umodem.c @@ -171,8 +171,9 @@ static struct cdevsw umodem_cdevsw = { /* maj */ UMODEM_CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; #endif diff --git a/sys/fs/fifofs/fifo_vnops.c b/sys/fs/fifofs/fifo_vnops.c index 453f2077bec7..79ee0aa7a3d9 100644 --- a/sys/fs/fifofs/fifo_vnops.c +++ b/sys/fs/fifofs/fifo_vnops.c @@ -71,21 +71,20 @@ static int fifo_read __P((struct vop_read_args *)); static int fifo_write __P((struct vop_write_args *)); static int fifo_ioctl __P((struct vop_ioctl_args *)); static int fifo_poll __P((struct vop_poll_args *)); +static int fifo_kqfilter __P((struct vop_kqfilter_args *)); static int fifo_bmap __P((struct vop_bmap_args *)); static int fifo_pathconf __P((struct vop_pathconf_args *)); static int fifo_advlock __P((struct vop_advlock_args *)); -static int filt_fiforattach(struct knote *kn); static void filt_fifordetach(struct knote *kn); static int filt_fiforead(struct knote *kn, long hint); -static int filt_fifowattach(struct knote *kn); static void filt_fifowdetach(struct knote *kn); static int filt_fifowrite(struct knote *kn, long hint); -struct filterops fifo_rwfiltops[] = { - { 1, filt_fiforattach, filt_fifordetach, filt_fiforead }, - { 1, filt_fifowattach, filt_fifowdetach, filt_fifowrite }, -}; +static struct filterops fiforead_filtops = + { 1, NULL, filt_fifordetach, filt_fiforead }; +static struct filterops fifowrite_filtops = + { 1, NULL, filt_fifowdetach, filt_fifowrite }; vop_t **fifo_vnodeop_p; static struct vnodeopv_entry_desc fifo_vnodeop_entries[] = { @@ -106,6 +105,7 @@ static struct vnodeopv_entry_desc fifo_vnodeop_entries[] = { { &vop_open_desc, (vop_t *) fifo_open }, { &vop_pathconf_desc, (vop_t *) fifo_pathconf }, { &vop_poll_desc, (vop_t *) fifo_poll }, + { &vop_kqfilter_desc, (vop_t *) fifo_kqfilter }, { &vop_print_desc, (vop_t *) fifo_print }, { &vop_read_desc, (vop_t *) fifo_read }, { &vop_readdir_desc, (vop_t *) fifo_badop }, @@ -354,22 +354,42 @@ fifo_ioctl(ap) return (0); } +/* ARGSUSED */ static int -filt_fiforattach(struct knote *kn) +fifo_kqfilter(ap) + struct vop_kqfilter_args /* { + struct vnode *a_vp; + struct knote *a_kn; + } */ *ap; { - struct vnode *vn = (struct vnode *)kn->kn_fp->f_data; - struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock; + struct socket *so = (struct socket *)ap->a_vp->v_fifoinfo->fi_readsock; + struct sockbuf *sb; + + switch (ap->a_kn->kn_filter) { + case EVFILT_READ: + ap->a_kn->kn_fop = &fiforead_filtops; + sb = &so->so_rcv; + break; + case EVFILT_WRITE: + ap->a_kn->kn_fop = &fifowrite_filtops; + sb = &so->so_snd; + break; + default: + return (1); + } + + ap->a_kn->kn_hook = (caddr_t)so; + + SLIST_INSERT_HEAD(&sb->sb_sel.si_note, ap->a_kn, kn_selnext); + sb->sb_flags |= SB_KNOTE; - SLIST_INSERT_HEAD(&so->so_rcv.sb_sel.si_note, kn, kn_selnext); - so->so_rcv.sb_flags |= SB_KNOTE; return (0); } static void filt_fifordetach(struct knote *kn) { - struct vnode *vn = (struct vnode *)kn->kn_fp->f_data; - struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock; + struct socket *so = (struct socket *)kn->kn_hook; SLIST_REMOVE(&so->so_rcv.sb_sel.si_note, kn, knote, kn_selnext); if (SLIST_EMPTY(&so->so_rcv.sb_sel.si_note)) @@ -379,8 +399,7 @@ filt_fifordetach(struct knote *kn) static int filt_fiforead(struct knote *kn, long hint) { - struct vnode *vn = (struct vnode *)kn->kn_fp->f_data; - struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock; + struct socket *so = (struct socket *)kn->kn_hook; kn->kn_data = so->so_rcv.sb_cc; if (so->so_state & SS_CANTRCVMORE) { @@ -391,22 +410,10 @@ filt_fiforead(struct knote *kn, long hint) return (kn->kn_data > 0); } -static int -filt_fifowattach(struct knote *kn) -{ - struct vnode *vn = (struct vnode *)kn->kn_fp->f_data; - struct socket *so = (struct socket *)vn->v_fifoinfo->fi_writesock; - - SLIST_INSERT_HEAD(&so->so_snd.sb_sel.si_note, kn, kn_selnext); - so->so_rcv.sb_flags |= SB_KNOTE; - return (0); -} - static void filt_fifowdetach(struct knote *kn) { - struct vnode *vn = (struct vnode *)kn->kn_fp->f_data; - struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock; + struct socket *so = (struct socket *)kn->kn_hook; SLIST_REMOVE(&so->so_snd.sb_sel.si_note, kn, knote, kn_selnext); if (SLIST_EMPTY(&so->so_snd.sb_sel.si_note)) @@ -416,8 +423,7 @@ filt_fifowdetach(struct knote *kn) static int filt_fifowrite(struct knote *kn, long hint) { - struct vnode *vn = (struct vnode *)kn->kn_fp->f_data; - struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock; + struct socket *so = (struct socket *)kn->kn_hook; kn->kn_data = sbspace(&so->so_snd); if (so->so_state & SS_CANTSENDMORE) { diff --git a/sys/fs/specfs/spec_vnops.c b/sys/fs/specfs/spec_vnops.c index dce82120cb4b..35a0a49f7bb7 100644 --- a/sys/fs/specfs/spec_vnops.c +++ b/sys/fs/specfs/spec_vnops.c @@ -62,6 +62,7 @@ static int spec_getpages __P((struct vop_getpages_args *)); static int spec_ioctl __P((struct vop_ioctl_args *)); static int spec_open __P((struct vop_open_args *)); static int spec_poll __P((struct vop_poll_args *)); +static int spec_kqfilter __P((struct vop_kqfilter_args *)); static int spec_print __P((struct vop_print_args *)); static int spec_read __P((struct vop_read_args *)); static int spec_strategy __P((struct vop_strategy_args *)); @@ -87,6 +88,7 @@ static struct vnodeopv_entry_desc spec_vnodeop_entries[] = { { &vop_open_desc, (vop_t *) spec_open }, { &vop_pathconf_desc, (vop_t *) vop_stdpathconf }, { &vop_poll_desc, (vop_t *) spec_poll }, + { &vop_kqfilter_desc, (vop_t *) spec_kqfilter }, { &vop_print_desc, (vop_t *) spec_print }, { &vop_read_desc, (vop_t *) spec_read }, { &vop_readdir_desc, (vop_t *) vop_panic }, @@ -330,6 +332,23 @@ spec_poll(ap) dev = ap->a_vp->v_rdev; return (*devsw(dev)->d_poll)(dev, ap->a_events, ap->a_p); } + +/* ARGSUSED */ +static int +spec_kqfilter(ap) + struct vop_kqfilter_args /* { + struct vnode *a_vp; + struct knote *a_kn; + } */ *ap; +{ + dev_t dev; + + dev = ap->a_vp->v_rdev; + if (devsw(dev)->d_flags & D_KQFILTER) + return (*devsw(dev)->d_kqfilter)(dev, ap->a_kn); + return (1); +} + /* * Synch buffers associated with a block device */ diff --git a/sys/i386/isa/cx.c b/sys/i386/isa/cx.c index 094dc6fe2674..1ec334b53799 100644 --- a/sys/i386/isa/cx.c +++ b/sys/i386/isa/cx.c @@ -100,8 +100,9 @@ struct cdevsw cx_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; #else struct tty *cx_tty [NCX*NCHAN]; /* tty data */ diff --git a/sys/i386/isa/cy.c b/sys/i386/isa/cy.c index 9a56e2df1010..7d7671d9419b 100644 --- a/sys/i386/isa/cy.c +++ b/sys/i386/isa/cy.c @@ -405,8 +405,9 @@ static struct cdevsw sio_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; static int comconsole = -1; diff --git a/sys/i386/isa/istallion.c b/sys/i386/isa/istallion.c index 61b7a5087060..41f66be833a3 100644 --- a/sys/i386/isa/istallion.c +++ b/sys/i386/isa/istallion.c @@ -654,8 +654,9 @@ static struct cdevsw stli_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; #endif diff --git a/sys/i386/isa/pcvt/pcvt_drv.c b/sys/i386/isa/pcvt/pcvt_drv.c index 74134bdeb301..eddc14ac5e85 100644 --- a/sys/i386/isa/pcvt/pcvt_drv.c +++ b/sys/i386/isa/pcvt/pcvt_drv.c @@ -108,8 +108,9 @@ static struct cdevsw vt_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; static int pcvt_probe(device_t dev); diff --git a/sys/i386/isa/rc.c b/sys/i386/isa/rc.c index a7e5ecbc8d43..6c1ca5d4aaca 100644 --- a/sys/i386/isa/rc.c +++ b/sys/i386/isa/rc.c @@ -107,8 +107,9 @@ static struct cdevsw rc_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; /* Per-board structure */ diff --git a/sys/i386/isa/rp.c b/sys/i386/isa/rp.c index 21c30cc2aad6..2740470d9796 100644 --- a/sys/i386/isa/rp.c +++ b/sys/i386/isa/rp.c @@ -816,8 +816,9 @@ static struct cdevsw rp_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; static int rp_controller_port = 0; diff --git a/sys/i386/isa/stallion.c b/sys/i386/isa/stallion.c index 73c2ce19b387..9a4ee7f62606 100644 --- a/sys/i386/isa/stallion.c +++ b/sys/i386/isa/stallion.c @@ -552,8 +552,9 @@ static struct cdevsw stl_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; static void stl_drvinit(void *unused) diff --git a/sys/isa/sio.c b/sys/isa/sio.c index ee3d4f180cf6..d8f02c9b5cee 100644 --- a/sys/isa/sio.c +++ b/sys/isa/sio.c @@ -388,8 +388,9 @@ static struct cdevsw sio_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; int comconsole = -1; diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 75ec0ee3f46e..45273463588d 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -93,6 +93,7 @@ static int badfo_ioctl __P((struct file *fp, u_long com, caddr_t data, struct proc *p)); static int badfo_poll __P((struct file *fp, int events, struct ucred *cred, struct proc *p)); +static int badfo_kqfilter __P((struct file *fp, struct knote *kn)); static int badfo_stat __P((struct file *fp, struct stat *sb, struct proc *p)); static int badfo_close __P((struct file *fp, struct proc *p)); @@ -1507,6 +1508,7 @@ struct fileops badfileops = { badfo_readwrite, badfo_ioctl, badfo_poll, + badfo_kqfilter, badfo_stat, badfo_close }; @@ -1545,6 +1547,15 @@ badfo_poll(fp, events, cred, p) return (0); } +static int +badfo_kqfilter(fp, kn) + struct file *fp; + struct knote *kn; +{ + + return (0); +} + static int badfo_stat(fp, sb, p) struct file *fp; diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index c1604d2af5c2..12fb698edd19 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -48,15 +48,6 @@ #include -static int filt_nullattach(struct knote *kn); -static int filt_rwtypattach(struct knote *kn); -static int filt_kqattach(struct knote *kn); -static void filt_kqdetach(struct knote *kn); -static int filt_kqueue(struct knote *kn, long hint); -static int filt_procattach(struct knote *kn); -static void filt_procdetach(struct knote *kn); -static int filt_proc(struct knote *kn, long hint); - static int kqueue_scan(struct file *fp, int maxevents, struct kevent *ulistp, const struct timespec *timeout, struct proc *p); @@ -68,10 +59,21 @@ static int kqueue_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p); static int kqueue_poll(struct file *fp, int events, struct ucred *cred, struct proc *p); +static int kqueue_kqfilter(struct file *fp, struct knote *kn); static int kqueue_stat(struct file *fp, struct stat *st, struct proc *p); static int kqueue_close(struct file *fp, struct proc *p); static void kqueue_wakeup(struct kqueue *kq); +static struct fileops kqueueops = { + kqueue_read, + kqueue_write, + kqueue_ioctl, + kqueue_poll, + kqueue_kqfilter, + kqueue_stat, + kqueue_close +}; + static void knote_attach(struct knote *kn, struct filedesc *fdp); static void knote_drop(struct knote *kn, struct proc *p); static void knote_enqueue(struct knote *kn); @@ -80,6 +82,20 @@ static void knote_init(void); static struct knote *knote_alloc(void); static void knote_free(struct knote *kn); +static void filt_kqdetach(struct knote *kn); +static int filt_kqueue(struct knote *kn, long hint); +static int filt_procattach(struct knote *kn); +static void filt_procdetach(struct knote *kn); +static int filt_proc(struct knote *kn, long hint); +static int filt_fileattach(struct knote *kn); + +static struct filterops kqread_filtops = + { 1, NULL, filt_kqdetach, filt_kqueue }; +static struct filterops proc_filtops = + { 0, filt_procattach, filt_procdetach, filt_proc }; +static struct filterops file_filtops = + { 1, filt_fileattach, NULL, NULL }; + static vm_zone_t knote_zone; #define KNOTE_ACTIVATE(kn) do { \ @@ -91,85 +107,38 @@ static vm_zone_t knote_zone; #define KN_HASHSIZE 64 /* XXX should be tunable */ #define KN_HASH(val, mask) (((val) ^ (val >> 8)) & (mask)) -static struct fileops kqueueops = { - kqueue_read, - kqueue_write, - kqueue_ioctl, - kqueue_poll, - kqueue_stat, - kqueue_close -}; - -extern struct filterops so_rwfiltops[]; -extern struct filterops fifo_rwfiltops[]; -extern struct filterops pipe_rwfiltops[]; -extern struct filterops vn_rwfiltops[]; - -static struct filterops kq_rwfiltops[] = { - { 1, filt_kqattach, filt_kqdetach, filt_kqueue }, - { 1, filt_nullattach, NULL, NULL }, -}; - extern struct filterops aio_filtops; extern struct filterops sig_filtops; -extern struct filterops vn_filtops; - -static struct filterops rwtype_filtops = - { 1, filt_rwtypattach, NULL, NULL }; -static struct filterops proc_filtops = - { 0, filt_procattach, filt_procdetach, filt_proc }; /* - * XXX - * These must match the order of defines in - */ -static struct filterops *rwtypfilt_sw[] = { - NULL, /* 0 */ - vn_rwfiltops, /* DTYPE_VNODE */ - so_rwfiltops, /* DTYPE_SOCKET */ - pipe_rwfiltops, /* DTYPE_PIPE */ - fifo_rwfiltops, /* DTYPE_FIFO */ - kq_rwfiltops, /* DTYPE_KQUEUE */ -}; - -/* - * table for for all system-defined filters. + * Table for for all system-defined filters. */ static struct filterops *sysfilt_ops[] = { - &rwtype_filtops, /* EVFILT_READ */ - &rwtype_filtops, /* EVFILT_WRITE */ + &file_filtops, /* EVFILT_READ */ + &file_filtops, /* EVFILT_WRITE */ &aio_filtops, /* EVFILT_AIO */ - &vn_filtops, /* EVFILT_VNODE */ + &file_filtops, /* EVFILT_VNODE */ &proc_filtops, /* EVFILT_PROC */ &sig_filtops, /* EVFILT_SIGNAL */ }; static int -filt_nullattach(struct knote *kn) +filt_fileattach(struct knote *kn) { - return (ENXIO); + + return (fo_kqfilter(kn->kn_fp, kn)); } -/* - * file-type specific attach routine for read/write filters - */ +/*ARGSUSED*/ static int -filt_rwtypattach(struct knote *kn) -{ - struct filterops *fops; - - fops = rwtypfilt_sw[kn->kn_fp->f_type]; - if (fops == NULL) - return (EINVAL); - kn->kn_fop = &fops[~kn->kn_filter]; /* convert to 0-base index */ - return (kn->kn_fop->f_attach(kn)); -} - -static int -filt_kqattach(struct knote *kn) +kqueue_kqfilter(struct file *fp, struct knote *kn) { struct kqueue *kq = (struct kqueue *)kn->kn_fp->f_data; + if (kn->kn_filter != EVFILT_READ) + return (1); + + kn->kn_fop = &kqread_filtops; SLIST_INSERT_HEAD(&kq->kq_sel.si_note, kn, kn_selnext); return (0); } diff --git a/sys/kern/subr_xxx.c b/sys/kern/subr_xxx.c index 6819fb38c57a..f3fd2ed2493b 100644 --- a/sys/kern/subr_xxx.c +++ b/sys/kern/subr_xxx.c @@ -133,6 +133,15 @@ noioctl(dev, cmd, data, flags, p) return (ENODEV); } +int +nokqfilter(dev, kn) + dev_t dev; + struct knote *kn; +{ + + return (ENODEV); +} + int nommap(dev, offset, nprot) dev_t dev; diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index cd9e3a7cf1a3..42786d95c14d 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -95,21 +95,24 @@ static int pipe_write __P((struct file *fp, struct uio *uio, static int pipe_close __P((struct file *fp, struct proc *p)); static int pipe_poll __P((struct file *fp, int events, struct ucred *cred, struct proc *p)); +static int pipe_kqfilter __P((struct file *fp, struct knote *kn)); static int pipe_stat __P((struct file *fp, struct stat *sb, struct proc *p)); static int pipe_ioctl __P((struct file *fp, u_long cmd, caddr_t data, struct proc *p)); -static struct fileops pipeops = - { pipe_read, pipe_write, pipe_ioctl, pipe_poll, pipe_stat, pipe_close }; +static struct fileops pipeops = { + pipe_read, pipe_write, pipe_ioctl, pipe_poll, pipe_kqfilter, + pipe_stat, pipe_close +}; -static int filt_pipeattach(struct knote *kn); static void filt_pipedetach(struct knote *kn); static int filt_piperead(struct knote *kn, long hint); static int filt_pipewrite(struct knote *kn, long hint); -struct filterops pipe_rwfiltops[] = { - { 1, filt_pipeattach, filt_pipedetach, filt_piperead }, - { 1, filt_pipeattach, filt_pipedetach, filt_pipewrite }, -}; +static struct filterops pipe_rfiltops = + { 1, NULL, filt_pipedetach, filt_piperead }; +static struct filterops pipe_wfiltops = + { 1, NULL, filt_pipedetach, filt_pipewrite }; + /* * Default pipe buffer size(s), this can be kind-of large now because pipe @@ -1186,11 +1189,23 @@ pipeclose(cpipe) } } +/*ARGSUSED*/ static int -filt_pipeattach(struct knote *kn) +pipe_kqfilter(struct file *fp, struct knote *kn) { struct pipe *rpipe = (struct pipe *)kn->kn_fp->f_data; + switch (kn->kn_filter) { + case EVFILT_READ: + kn->kn_fop = &pipe_rfiltops; + break; + case EVFILT_WRITE: + kn->kn_fop = &pipe_wfiltops; + break; + default: + return (1); + } + SLIST_INSERT_HEAD(&rpipe->pipe_sel.si_note, kn, kn_selnext); return (0); } diff --git a/sys/kern/sys_socket.c b/sys/kern/sys_socket.c index f58720b7e4a5..e4db298b339f 100644 --- a/sys/kern/sys_socket.c +++ b/sys/kern/sys_socket.c @@ -50,8 +50,10 @@ #include #include -struct fileops socketops = - { soo_read, soo_write, soo_ioctl, soo_poll, soo_stat, soo_close }; +struct fileops socketops = { + soo_read, soo_write, soo_ioctl, soo_poll, sokqfilter, + soo_stat, soo_close +}; /* ARGSUSED */ int diff --git a/sys/kern/tty.c b/sys/kern/tty.c index b815e7c75d5a..b5b8a9cd13b8 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -113,6 +113,10 @@ static void ttyrub __P((int c, struct tty *tp)); static void ttyrubo __P((struct tty *tp, int cnt)); static void ttyunblock __P((struct tty *tp)); static int ttywflush __P((struct tty *tp)); +static int filt_ttyread __P((struct knote *kn, long hint)); +static void filt_ttyrdetach __P((struct knote *kn)); +static int filt_ttywrite __P((struct knote *kn, long hint)); +static void filt_ttywdetach __P((struct knote *kn)); /* * Table with character classes and parity. The 8th bit indicates parity, @@ -1092,6 +1096,89 @@ ttypoll(dev, events, p) return (revents); } +static struct filterops ttyread_filtops = + { 1, NULL, filt_ttyrdetach, filt_ttyread }; +static struct filterops ttywrite_filtops = + { 1, NULL, filt_ttywdetach, filt_ttywrite }; + +int +ttykqfilter(dev, kn) + dev_t dev; + struct knote *kn; +{ + struct tty *tp = dev->si_tty; + struct klist *klist; + int s; + + switch (kn->kn_filter) { + case EVFILT_READ: + klist = &tp->t_rsel.si_note; + kn->kn_fop = &ttyread_filtops; + break; + case EVFILT_WRITE: + klist = &tp->t_wsel.si_note; + kn->kn_fop = &ttywrite_filtops; + break; + default: + return (1); + } + + kn->kn_hook = (caddr_t)dev; + + s = spltty(); + SLIST_INSERT_HEAD(klist, kn, kn_selnext); + splx(s); + + return (0); +} + +static void +filt_ttyrdetach(struct knote *kn) +{ + struct tty *tp = ((dev_t)kn->kn_hook)->si_tty; + int s = spltty(); + + SLIST_REMOVE(&tp->t_rsel.si_note, kn, knote, kn_selnext); + splx(s); +} + +static int +filt_ttyread(struct knote *kn, long hint) +{ + struct tty *tp = ((dev_t)kn->kn_hook)->si_tty; + + kn->kn_data = ttnread(tp); + if (ISSET(tp->t_state, TS_ZOMBIE)) { + kn->kn_flags |= EV_EOF; + return (1); + } + return (kn->kn_data > 0); +} + +static void +filt_ttywdetach(struct knote *kn) +{ + struct tty *tp = ((dev_t)kn->kn_hook)->si_tty; + int s = spltty(); + + SLIST_REMOVE(&tp->t_wsel.si_note, kn, knote, kn_selnext); + splx(s); +} + +static int +filt_ttywrite(kn, hint) + struct knote *kn; + long hint; +{ + struct tty *tp = ((dev_t)kn->kn_hook)->si_tty; + + kn->kn_data = tp->t_outq.c_cc; + if (ISSET(tp->t_state, TS_ZOMBIE)) + return (1); + return (kn->kn_data <= tp->t_olowat && + ISSET(tp->t_state, TS_CONNECTED)); +} + /* * Must be called at spltty(). */ @@ -2118,6 +2205,7 @@ ttwakeup(tp) if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL) pgsigio(tp->t_sigio, SIGIO, (tp->t_session != NULL)); wakeup(TSA_HUP_OR_INPUT(tp)); + KNOTE(&tp->t_rsel.si_note, 0); } /* @@ -2142,6 +2230,7 @@ ttwwakeup(tp) CLR(tp->t_state, TS_SO_OLOWAT); wakeup(TSA_OLOWAT(tp)); } + KNOTE(&tp->t_wsel.si_note, 0); } /* diff --git a/sys/kern/tty_cons.c b/sys/kern/tty_cons.c index 784fecad98e2..9aa2c23386d6 100644 --- a/sys/kern/tty_cons.c +++ b/sys/kern/tty_cons.c @@ -58,6 +58,7 @@ static d_read_t cnread; static d_write_t cnwrite; static d_ioctl_t cnioctl; static d_poll_t cnpoll; +static d_kqfilter_t cnkqfilter; #define CDEV_MAJOR 0 static struct cdevsw cn_cdevsw = { @@ -73,8 +74,9 @@ static struct cdevsw cn_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ cnkqfilter, }; static dev_t cn_dev_t; /* seems to be never really used */ @@ -398,6 +400,20 @@ cnpoll(dev, events, p) return ((*devsw(dev)->d_poll)(dev, events, p)); } +static int +cnkqfilter(dev, kn) + dev_t dev; + struct knote *kn; +{ + if ((cn_tab == NULL) || cn_mute) + return (1); + + dev = cn_tab->cn_dev; + if (devsw(dev)->d_flags & D_KQFILTER) + return ((*devsw(dev)->d_kqfilter)(dev, kn)); + return (1); +} + int cngetc() { diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c index f7a4370ffda5..b6063fc620ab 100644 --- a/sys/kern/tty_pty.c +++ b/sys/kern/tty_pty.c @@ -86,8 +86,9 @@ static struct cdevsw pts_cdevsw = { /* maj */ CDEV_MAJOR_S, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; #define CDEV_MAJOR_C 6 @@ -104,8 +105,9 @@ static struct cdevsw ptc_cdevsw = { /* maj */ CDEV_MAJOR_C, /* dump */ nodump, /* psize */ nopsize, - /* flags */ D_TTY, - /* bmaj */ -1 + /* flags */ D_TTY | D_KQFILTER, + /* bmaj */ -1, + /* kqfilter */ ttykqfilter, }; #define BUFSIZ 100 /* Chunk size iomoved to/from user */ diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index d8a95cf2efd5..85667de0464c 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -64,21 +64,18 @@ static int do_setopt_accept_filter(struct socket *so, struct sockopt *sopt); #endif -static int filt_sorattach(struct knote *kn); static void filt_sordetach(struct knote *kn); static int filt_soread(struct knote *kn, long hint); -static int filt_sowattach(struct knote *kn); static void filt_sowdetach(struct knote *kn); static int filt_sowrite(struct knote *kn, long hint); static int filt_solisten(struct knote *kn, long hint); static struct filterops solisten_filtops = - { 1, filt_sorattach, filt_sordetach, filt_solisten }; - -struct filterops so_rwfiltops[] = { - { 1, filt_sorattach, filt_sordetach, filt_soread }, - { 1, filt_sowattach, filt_sowdetach, filt_sowrite }, -}; + { 1, NULL, filt_sordetach, filt_solisten }; +static struct filterops soread_filtops = + { 1, NULL, filt_sordetach, filt_soread }; +static struct filterops sowrite_filtops = + { 1, NULL, filt_sowdetach, filt_sowrite }; struct vm_zone *socket_zone; so_gen_t so_gencnt; /* generation count for sockets */ @@ -1534,16 +1531,32 @@ sopoll(struct socket *so, int events, struct ucred *cred, struct proc *p) return (revents); } -static int -filt_sorattach(struct knote *kn) +int +sokqfilter(struct file *fp, struct knote *kn) { struct socket *so = (struct socket *)kn->kn_fp->f_data; - int s = splnet(); + struct sockbuf *sb; + int s; - if (so->so_options & SO_ACCEPTCONN) - kn->kn_fop = &solisten_filtops; - SLIST_INSERT_HEAD(&so->so_rcv.sb_sel.si_note, kn, kn_selnext); - so->so_rcv.sb_flags |= SB_KNOTE; + switch (kn->kn_filter) { + case EVFILT_READ: + if (so->so_options & SO_ACCEPTCONN) + kn->kn_fop = &solisten_filtops; + else + kn->kn_fop = &soread_filtops; + sb = &so->so_rcv; + break; + case EVFILT_WRITE: + kn->kn_fop = &sowrite_filtops; + sb = &so->so_snd; + break; + default: + return (1); + } + + s = splnet(); + SLIST_INSERT_HEAD(&sb->sb_sel.si_note, kn, kn_selnext); + sb->sb_flags |= SB_KNOTE; splx(s); return (0); } @@ -1576,18 +1589,6 @@ filt_soread(struct knote *kn, long hint) return (kn->kn_data >= so->so_rcv.sb_lowat); } -static int -filt_sowattach(struct knote *kn) -{ - struct socket *so = (struct socket *)kn->kn_fp->f_data; - int s = splnet(); - - SLIST_INSERT_HEAD(&so->so_snd.sb_sel.si_note, kn, kn_selnext); - so->so_snd.sb_flags |= SB_KNOTE; - splx(s); - return (0); -} - static void filt_sowdetach(struct knote *kn) { diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 01751233e4a7..760df67c3efc 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -55,9 +55,6 @@ #include #include -#include -#include - static int vn_closefile __P((struct file *fp, struct proc *p)); static int vn_ioctl __P((struct file *fp, u_long com, caddr_t data, struct proc *p)); @@ -65,30 +62,14 @@ static int vn_read __P((struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct proc *p)); static int vn_poll __P((struct file *fp, int events, struct ucred *cred, struct proc *p)); +static int vn_kqfilter __P((struct file *fp, struct knote *kn)); static int vn_statfile __P((struct file *fp, struct stat *sb, struct proc *p)); static int vn_write __P((struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct proc *p)); -struct fileops vnops = - { vn_read, vn_write, vn_ioctl, vn_poll, vn_statfile, vn_closefile }; - -static int filt_nullattach(struct knote *kn); -static int filt_vnattach(struct knote *kn); -static void filt_vndetach(struct knote *kn); -static int filt_vnode(struct knote *kn, long hint); -static int filt_vnread(struct knote *kn, long hint); - -struct filterops vn_filtops = - { 1, filt_vnattach, filt_vndetach, filt_vnode }; - -/* - * XXX - * filt_vnread is ufs-specific, so the attach routine should really - * switch out to different filterops based on the vn filetype - */ -struct filterops vn_rwfiltops[] = { - { 1, filt_vnattach, filt_vndetach, filt_vnread }, - { 1, filt_nullattach, NULL, NULL }, +struct fileops vnops = { + vn_read, vn_write, vn_ioctl, vn_poll, vn_kqfilter, + vn_statfile, vn_closefile }; /* @@ -815,66 +796,10 @@ vfs_write_resume(mp) } static int -filt_vnattach(struct knote *kn) -{ - struct vnode *vp; - - if (kn->kn_fp->f_type != DTYPE_VNODE && - kn->kn_fp->f_type != DTYPE_FIFO) - return (EBADF); - - vp = (struct vnode *)kn->kn_fp->f_data; - - /* - * XXX - * this is a hack simply to cause the filter attach to fail - * for non-ufs filesystems, until the support for them is done. - */ - if ((vp)->v_tag != VT_UFS) - return (EOPNOTSUPP); - - mtx_lock(&vp->v_pollinfo.vpi_lock); - SLIST_INSERT_HEAD(&vp->v_pollinfo.vpi_selinfo.si_note, kn, kn_selnext); - mtx_unlock(&vp->v_pollinfo.vpi_lock); - - return (0); -} - -static void -filt_vndetach(struct knote *kn) -{ - struct vnode *vp = (struct vnode *)kn->kn_fp->f_data; - - mtx_lock(&vp->v_pollinfo.vpi_lock); - SLIST_REMOVE(&vp->v_pollinfo.vpi_selinfo.si_note, - kn, knote, kn_selnext); - mtx_unlock(&vp->v_pollinfo.vpi_lock); -} - -static int -filt_vnode(struct knote *kn, long hint) +vn_kqfilter(struct file *fp, struct knote *kn) { - if (kn->kn_sfflags & hint) - kn->kn_fflags |= hint; - return (kn->kn_fflags != 0); -} - -static int -filt_nullattach(struct knote *kn) -{ - return (ENXIO); -} - -/*ARGSUSED*/ -static int -filt_vnread(struct knote *kn, long hint) -{ - struct vnode *vp = (struct vnode *)kn->kn_fp->f_data; - struct inode *ip = VTOI(vp); - - kn->kn_data = ip->i_size - kn->kn_fp->f_offset; - return (kn->kn_data != 0); + return (VOP_KQFILTER(((struct vnode *)fp->f_data), kn)); } /* diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src index 82a1c0aeff48..c8f91f1367d0 100644 --- a/sys/kern/vnode_if.src +++ b/sys/kern/vnode_if.src @@ -221,6 +221,14 @@ vop_poll { IN struct proc *p; }; +# +#% kqfilter vp U U U +# +vop_kqfilter { + IN struct vnode *vp; + IN struct knote *kn; +}; + # #% revoke vp U U U # diff --git a/sys/miscfs/fifofs/fifo_vnops.c b/sys/miscfs/fifofs/fifo_vnops.c index 453f2077bec7..79ee0aa7a3d9 100644 --- a/sys/miscfs/fifofs/fifo_vnops.c +++ b/sys/miscfs/fifofs/fifo_vnops.c @@ -71,21 +71,20 @@ static int fifo_read __P((struct vop_read_args *)); static int fifo_write __P((struct vop_write_args *)); static int fifo_ioctl __P((struct vop_ioctl_args *)); static int fifo_poll __P((struct vop_poll_args *)); +static int fifo_kqfilter __P((struct vop_kqfilter_args *)); static int fifo_bmap __P((struct vop_bmap_args *)); static int fifo_pathconf __P((struct vop_pathconf_args *)); static int fifo_advlock __P((struct vop_advlock_args *)); -static int filt_fiforattach(struct knote *kn); static void filt_fifordetach(struct knote *kn); static int filt_fiforead(struct knote *kn, long hint); -static int filt_fifowattach(struct knote *kn); static void filt_fifowdetach(struct knote *kn); static int filt_fifowrite(struct knote *kn, long hint); -struct filterops fifo_rwfiltops[] = { - { 1, filt_fiforattach, filt_fifordetach, filt_fiforead }, - { 1, filt_fifowattach, filt_fifowdetach, filt_fifowrite }, -}; +static struct filterops fiforead_filtops = + { 1, NULL, filt_fifordetach, filt_fiforead }; +static struct filterops fifowrite_filtops = + { 1, NULL, filt_fifowdetach, filt_fifowrite }; vop_t **fifo_vnodeop_p; static struct vnodeopv_entry_desc fifo_vnodeop_entries[] = { @@ -106,6 +105,7 @@ static struct vnodeopv_entry_desc fifo_vnodeop_entries[] = { { &vop_open_desc, (vop_t *) fifo_open }, { &vop_pathconf_desc, (vop_t *) fifo_pathconf }, { &vop_poll_desc, (vop_t *) fifo_poll }, + { &vop_kqfilter_desc, (vop_t *) fifo_kqfilter }, { &vop_print_desc, (vop_t *) fifo_print }, { &vop_read_desc, (vop_t *) fifo_read }, { &vop_readdir_desc, (vop_t *) fifo_badop }, @@ -354,22 +354,42 @@ fifo_ioctl(ap) return (0); } +/* ARGSUSED */ static int -filt_fiforattach(struct knote *kn) +fifo_kqfilter(ap) + struct vop_kqfilter_args /* { + struct vnode *a_vp; + struct knote *a_kn; + } */ *ap; { - struct vnode *vn = (struct vnode *)kn->kn_fp->f_data; - struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock; + struct socket *so = (struct socket *)ap->a_vp->v_fifoinfo->fi_readsock; + struct sockbuf *sb; + + switch (ap->a_kn->kn_filter) { + case EVFILT_READ: + ap->a_kn->kn_fop = &fiforead_filtops; + sb = &so->so_rcv; + break; + case EVFILT_WRITE: + ap->a_kn->kn_fop = &fifowrite_filtops; + sb = &so->so_snd; + break; + default: + return (1); + } + + ap->a_kn->kn_hook = (caddr_t)so; + + SLIST_INSERT_HEAD(&sb->sb_sel.si_note, ap->a_kn, kn_selnext); + sb->sb_flags |= SB_KNOTE; - SLIST_INSERT_HEAD(&so->so_rcv.sb_sel.si_note, kn, kn_selnext); - so->so_rcv.sb_flags |= SB_KNOTE; return (0); } static void filt_fifordetach(struct knote *kn) { - struct vnode *vn = (struct vnode *)kn->kn_fp->f_data; - struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock; + struct socket *so = (struct socket *)kn->kn_hook; SLIST_REMOVE(&so->so_rcv.sb_sel.si_note, kn, knote, kn_selnext); if (SLIST_EMPTY(&so->so_rcv.sb_sel.si_note)) @@ -379,8 +399,7 @@ filt_fifordetach(struct knote *kn) static int filt_fiforead(struct knote *kn, long hint) { - struct vnode *vn = (struct vnode *)kn->kn_fp->f_data; - struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock; + struct socket *so = (struct socket *)kn->kn_hook; kn->kn_data = so->so_rcv.sb_cc; if (so->so_state & SS_CANTRCVMORE) { @@ -391,22 +410,10 @@ filt_fiforead(struct knote *kn, long hint) return (kn->kn_data > 0); } -static int -filt_fifowattach(struct knote *kn) -{ - struct vnode *vn = (struct vnode *)kn->kn_fp->f_data; - struct socket *so = (struct socket *)vn->v_fifoinfo->fi_writesock; - - SLIST_INSERT_HEAD(&so->so_snd.sb_sel.si_note, kn, kn_selnext); - so->so_rcv.sb_flags |= SB_KNOTE; - return (0); -} - static void filt_fifowdetach(struct knote *kn) { - struct vnode *vn = (struct vnode *)kn->kn_fp->f_data; - struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock; + struct socket *so = (struct socket *)kn->kn_hook; SLIST_REMOVE(&so->so_snd.sb_sel.si_note, kn, knote, kn_selnext); if (SLIST_EMPTY(&so->so_snd.sb_sel.si_note)) @@ -416,8 +423,7 @@ filt_fifowdetach(struct knote *kn) static int filt_fifowrite(struct knote *kn, long hint) { - struct vnode *vn = (struct vnode *)kn->kn_fp->f_data; - struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock; + struct socket *so = (struct socket *)kn->kn_hook; kn->kn_data = sbspace(&so->so_snd); if (so->so_state & SS_CANTSENDMORE) { diff --git a/sys/miscfs/specfs/spec_vnops.c b/sys/miscfs/specfs/spec_vnops.c index dce82120cb4b..35a0a49f7bb7 100644 --- a/sys/miscfs/specfs/spec_vnops.c +++ b/sys/miscfs/specfs/spec_vnops.c @@ -62,6 +62,7 @@ static int spec_getpages __P((struct vop_getpages_args *)); static int spec_ioctl __P((struct vop_ioctl_args *)); static int spec_open __P((struct vop_open_args *)); static int spec_poll __P((struct vop_poll_args *)); +static int spec_kqfilter __P((struct vop_kqfilter_args *)); static int spec_print __P((struct vop_print_args *)); static int spec_read __P((struct vop_read_args *)); static int spec_strategy __P((struct vop_strategy_args *)); @@ -87,6 +88,7 @@ static struct vnodeopv_entry_desc spec_vnodeop_entries[] = { { &vop_open_desc, (vop_t *) spec_open }, { &vop_pathconf_desc, (vop_t *) vop_stdpathconf }, { &vop_poll_desc, (vop_t *) spec_poll }, + { &vop_kqfilter_desc, (vop_t *) spec_kqfilter }, { &vop_print_desc, (vop_t *) spec_print }, { &vop_read_desc, (vop_t *) spec_read }, { &vop_readdir_desc, (vop_t *) vop_panic }, @@ -330,6 +332,23 @@ spec_poll(ap) dev = ap->a_vp->v_rdev; return (*devsw(dev)->d_poll)(dev, ap->a_events, ap->a_p); } + +/* ARGSUSED */ +static int +spec_kqfilter(ap) + struct vop_kqfilter_args /* { + struct vnode *a_vp; + struct knote *a_kn; + } */ *ap; +{ + dev_t dev; + + dev = ap->a_vp->v_rdev; + if (devsw(dev)->d_flags & D_KQFILTER) + return (*devsw(dev)->d_kqfilter)(dev, ap->a_kn); + return (1); +} + /* * Synch buffers associated with a block device */ diff --git a/sys/sys/conf.h b/sys/sys/conf.h index b277c9a76fdc..81ea6afc2f4d 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -105,6 +105,7 @@ struct bio; struct buf; struct proc; struct uio; +struct knote; typedef int d_open_t __P((dev_t dev, int oflags, int devtype, struct proc *p)); typedef int d_close_t __P((dev_t dev, int fflag, int devtype, struct proc *p)); @@ -118,6 +119,7 @@ typedef int d_psize_t __P((dev_t dev)); typedef int d_read_t __P((dev_t dev, struct uio *uio, int ioflag)); typedef int d_write_t __P((dev_t dev, struct uio *uio, int ioflag)); typedef int d_poll_t __P((dev_t dev, int events, struct proc *p)); +typedef int d_kqfilter_t __P((dev_t dev, struct knote *kn)); typedef int d_mmap_t __P((dev_t dev, vm_offset_t offset, int nprot)); typedef int l_open_t __P((dev_t dev, struct tty *tp)); @@ -169,11 +171,12 @@ typedef int l_modem_t __P((struct tty *tp, int flag)); /* * Flags for d_flags. */ -#define D_MEMDISK 0x10000 /* memory type disk */ -#define D_NAGGED 0x20000 /* nagged about missing make_dev() */ -#define D_CANFREE 0x40000 /* can free blocks */ -#define D_TRACKCLOSE 0x80000 /* track all closes */ -#define D_MMAP_ANON 0x100000 /* special treatment in vm_mmap.c */ +#define D_MEMDISK 0x00010000 /* memory type disk */ +#define D_NAGGED 0x00020000 /* nagged about missing make_dev() */ +#define D_CANFREE 0x00040000 /* can free blocks */ +#define D_TRACKCLOSE 0x00080000 /* track all closes */ +#define D_MMAP_ANON 0x00100000 /* special treatment in vm_mmap.c */ +#define D_KQFILTER 0x00200000 /* has kqfilter entry */ /* * Character device switch table @@ -194,6 +197,8 @@ struct cdevsw { u_int d_flags; /* This following field is deprecated. Please don't initialize */ int d_XXXbmaj; + /* additions below are not binary compatible with 4.2 and below */ + d_kqfilter_t *d_kqfilter; }; /* @@ -241,6 +246,7 @@ d_read_t noread; d_write_t nowrite; d_ioctl_t noioctl; d_mmap_t nommap; +d_kqfilter_t nokqfilter; #define nostrategy ((d_strategy_t *)NULL) #define nopoll seltrue diff --git a/sys/sys/event.h b/sys/sys/event.h index 6182bccd0926..9f216786386d 100644 --- a/sys/sys/event.h +++ b/sys/sys/event.h @@ -127,6 +127,7 @@ struct knote { struct proc *p_proc; /* proc pointer */ } kn_ptr; struct filterops *kn_fop; + caddr_t kn_hook; #define KN_ACTIVE 0x01 /* event has been triggered */ #define KN_QUEUED 0x02 /* event is on queue */ #define KN_DISABLED 0x04 /* event is disabled */ diff --git a/sys/sys/file.h b/sys/sys/file.h index a92370a3be5d..207f22788e72 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -48,6 +48,7 @@ struct stat; struct proc; struct uio; +struct knote; /* * Kernel descriptor table. @@ -77,6 +78,8 @@ struct file { caddr_t data, struct proc *p)); int (*fo_poll) __P((struct file *fp, int events, struct ucred *cred, struct proc *p)); + int (*fo_kqfilter) __P((struct file *fp, + struct knote *kn)); int (*fo_stat) __P((struct file *fp, struct stat *sb, struct proc *p)); int (*fo_close) __P((struct file *fp, struct proc *p)); @@ -126,6 +129,7 @@ static __inline int fo_poll __P((struct file *fp, int events, static __inline int fo_stat __P((struct file *fp, struct stat *sb, struct proc *p)); static __inline int fo_close __P((struct file *fp, struct proc *p)); +static __inline int fo_kqfilter __P((struct file *fp, struct knote *kn)); static __inline int fo_read(fp, uio, cred, flags, p) @@ -212,6 +216,15 @@ fo_close(fp, p) return ((*fp->f_ops->fo_close)(fp, p)); } +static __inline int +fo_kqfilter(fp, kn) + struct file *fp; + struct knote *kn; +{ + + return ((*fp->f_ops->fo_kqfilter)(fp, kn)); +} + #endif /* _KERNEL */ #endif /* !SYS_FILE_H */ diff --git a/sys/sys/linedisc.h b/sys/sys/linedisc.h index b277c9a76fdc..81ea6afc2f4d 100644 --- a/sys/sys/linedisc.h +++ b/sys/sys/linedisc.h @@ -105,6 +105,7 @@ struct bio; struct buf; struct proc; struct uio; +struct knote; typedef int d_open_t __P((dev_t dev, int oflags, int devtype, struct proc *p)); typedef int d_close_t __P((dev_t dev, int fflag, int devtype, struct proc *p)); @@ -118,6 +119,7 @@ typedef int d_psize_t __P((dev_t dev)); typedef int d_read_t __P((dev_t dev, struct uio *uio, int ioflag)); typedef int d_write_t __P((dev_t dev, struct uio *uio, int ioflag)); typedef int d_poll_t __P((dev_t dev, int events, struct proc *p)); +typedef int d_kqfilter_t __P((dev_t dev, struct knote *kn)); typedef int d_mmap_t __P((dev_t dev, vm_offset_t offset, int nprot)); typedef int l_open_t __P((dev_t dev, struct tty *tp)); @@ -169,11 +171,12 @@ typedef int l_modem_t __P((struct tty *tp, int flag)); /* * Flags for d_flags. */ -#define D_MEMDISK 0x10000 /* memory type disk */ -#define D_NAGGED 0x20000 /* nagged about missing make_dev() */ -#define D_CANFREE 0x40000 /* can free blocks */ -#define D_TRACKCLOSE 0x80000 /* track all closes */ -#define D_MMAP_ANON 0x100000 /* special treatment in vm_mmap.c */ +#define D_MEMDISK 0x00010000 /* memory type disk */ +#define D_NAGGED 0x00020000 /* nagged about missing make_dev() */ +#define D_CANFREE 0x00040000 /* can free blocks */ +#define D_TRACKCLOSE 0x00080000 /* track all closes */ +#define D_MMAP_ANON 0x00100000 /* special treatment in vm_mmap.c */ +#define D_KQFILTER 0x00200000 /* has kqfilter entry */ /* * Character device switch table @@ -194,6 +197,8 @@ struct cdevsw { u_int d_flags; /* This following field is deprecated. Please don't initialize */ int d_XXXbmaj; + /* additions below are not binary compatible with 4.2 and below */ + d_kqfilter_t *d_kqfilter; }; /* @@ -241,6 +246,7 @@ d_read_t noread; d_write_t nowrite; d_ioctl_t noioctl; d_mmap_t nommap; +d_kqfilter_t nokqfilter; #define nostrategy ((d_strategy_t *)NULL) #define nopoll seltrue diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h index 09014182bd3e..215286e5df93 100644 --- a/sys/sys/socketvar.h +++ b/sys/sys/socketvar.h @@ -305,6 +305,7 @@ struct sockaddr; struct stat; struct ucred; struct uio; +struct knote; /* * File operations on sockets. @@ -319,6 +320,7 @@ int soo_ioctl __P((struct file *fp, u_long cmd, caddr_t data, int soo_poll __P((struct file *fp, int events, struct ucred *cred, struct proc *p)); int soo_stat __P((struct file *fp, struct stat *ub, struct proc *p)); +int sokqfilter __P((struct file *fp, struct knote *kn)); /* * From uipc_socket and friends diff --git a/sys/sys/tty.h b/sys/sys/tty.h index afd7854b71f1..0a876cbf13dc 100644 --- a/sys/sys/tty.h +++ b/sys/sys/tty.h @@ -263,6 +263,7 @@ struct tty *ttymalloc __P((struct tty *tp)); int ttymodem __P((struct tty *tp, int flag)); int ttyopen __P((dev_t device, struct tty *tp)); int ttypoll __P((dev_t dev, int events, struct proc *p)); +int ttykqfilter __P((dev_t dev, struct knote *kn)); int ttyread __P((dev_t dev, struct uio *uio, int flag)); void ttyregister __P((struct tty *tp)); int ttysleep __P((struct tty *tp, void *chan, int pri, char *wmesg, diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index 134e356bfb0e..2244df33b19e 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -61,6 +61,8 @@ #include +#include /* XXX */ + #include #include @@ -103,6 +105,10 @@ static int ufsfifo_write __P((struct vop_write_args *)); static int ufsspec_close __P((struct vop_close_args *)); static int ufsspec_read __P((struct vop_read_args *)); static int ufsspec_write __P((struct vop_write_args *)); +static int filt_ufsread __P((struct knote *kn, long hint)); +static int filt_ufsvnode __P((struct knote *kn, long hint)); +static void filt_ufsdetach __P((struct knote *kn)); +static int ufs_kqfilter __P((struct vop_kqfilter_args *ap)); union _qcvt { int64_t qcvt; @@ -2176,6 +2182,71 @@ ufs_missingop(ap) return (EOPNOTSUPP); } +static struct filterops ufsread_filtops = + { 1, NULL, filt_ufsdetach, filt_ufsread }; +static struct filterops ufsvnode_filtops = + { 1, NULL, filt_ufsdetach, filt_ufsvnode }; + +static int +ufs_kqfilter(ap) + struct vop_kqfilter_args /* { + struct vnode *a_vp; + struct knote *a_kn; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct knote *kn = ap->a_kn; + + switch (kn->kn_filter) { + case EVFILT_READ: + kn->kn_fop = &ufsread_filtops; + break; + case EVFILT_VNODE: + kn->kn_fop = &ufsvnode_filtops; + break; + default: + return (1); + } + + kn->kn_hook = (caddr_t)vp; + + mtx_lock(&vp->v_pollinfo.vpi_lock); + SLIST_INSERT_HEAD(&vp->v_pollinfo.vpi_selinfo.si_note, kn, kn_selnext); + mtx_unlock(&vp->v_pollinfo.vpi_lock); + + return (0); +} + +static void +filt_ufsdetach(struct knote *kn) +{ + struct vnode *vp = (struct vnode *)kn->kn_hook; + + mtx_lock(&vp->v_pollinfo.vpi_lock); + SLIST_REMOVE(&vp->v_pollinfo.vpi_selinfo.si_note, kn, knote, kn_link); + mtx_unlock(&vp->v_pollinfo.vpi_lock); +} + +/*ARGSUSED*/ +static int +filt_ufsread(struct knote *kn, long hint) +{ + struct vnode *vp = (struct vnode *)kn->kn_hook; + struct inode *ip = VTOI(vp); + + kn->kn_data = ip->i_size - kn->kn_fp->f_offset; + return (kn->kn_data != 0); +} + +static int +filt_ufsvnode(struct knote *kn, long hint) +{ + + if (kn->kn_sfflags & hint) + kn->kn_fflags |= hint; + return (kn->kn_fflags != 0); +} + /* Global vfs data structures for ufs. */ static vop_t **ufs_vnodeop_p; static struct vnodeopv_entry_desc ufs_vnodeop_entries[] = { @@ -2201,6 +2272,7 @@ static struct vnodeopv_entry_desc ufs_vnodeop_entries[] = { { &vop_open_desc, (vop_t *) ufs_open }, { &vop_pathconf_desc, (vop_t *) ufs_pathconf }, { &vop_poll_desc, (vop_t *) vop_stdpoll }, + { &vop_kqfilter_desc, (vop_t *) ufs_kqfilter }, { &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount }, { &vop_print_desc, (vop_t *) ufs_print }, { &vop_readdir_desc, (vop_t *) ufs_readdir },