From owner-freebsd-bugs@FreeBSD.ORG Wed Mar 1 11:20:05 2006 Return-Path: X-Original-To: freebsd-bugs@hub.freebsd.org Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 0D1AE16A420 for ; Wed, 1 Mar 2006 11:20:05 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 74CF643D46 for ; Wed, 1 Mar 2006 11:20:04 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.4/8.13.4) with ESMTP id k21BK40f047428 for ; Wed, 1 Mar 2006 11:20:04 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.4/8.13.4/Submit) id k21BK40x047425; Wed, 1 Mar 2006 11:20:04 GMT (envelope-from gnats) Resent-Date: Wed, 1 Mar 2006 11:20:04 GMT Resent-Message-Id: <200603011120.k21BK40x047425@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Vilmos Nebehaj Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id CCCC716A420 for ; Wed, 1 Mar 2006 11:14:23 +0000 (GMT) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (www.freebsd.org [216.136.204.117]) by mx1.FreeBSD.org (Postfix) with ESMTP id 871A343D46 for ; Wed, 1 Mar 2006 11:14:23 +0000 (GMT) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (localhost [127.0.0.1]) by www.freebsd.org (8.13.1/8.13.1) with ESMTP id k21BEN89038406 for ; Wed, 1 Mar 2006 11:14:23 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.13.1/8.13.1/Submit) id k21BEMSR038405; Wed, 1 Mar 2006 11:14:22 GMT (envelope-from nobody) Message-Id: <200603011114.k21BEMSR038405@www.freebsd.org> Date: Wed, 1 Mar 2006 11:14:22 GMT From: Vilmos Nebehaj To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-2.3 Cc: Subject: kern/93976: if_tun doesn't handle kqueue(2) X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 01 Mar 2006 11:20:05 -0000 >Number: 93976 >Category: kern >Synopsis: if_tun doesn't handle kqueue(2) >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Wed Mar 01 11:20:03 GMT 2006 >Closed-Date: >Last-Modified: >Originator: Vilmos Nebehaj >Release: FreeBSD 6.0 >Organization: >Environment: FreeBSD oszoo.oszoo 6.0-RELEASE-p4 FreeBSD 6.0-RELEASE-p4 #0: Mon Feb 27 16:55:18 CET 2006 root@oszoo.oszoo:/usr/obj/usr/src/sys/GENERIC i386 >Description: The same as with if_tap in http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/93897 . Kevent returns an error if someone tries to use it on a tun device (/dev/tunX), because kqueue bits are missing from if_tun.c.I've prepared a patch to address this issue: http://innoidea.com/~vili/if_tun.diff , it cleanly applies against -CURRENT and RELENG_6_0 too. Index: if_tun.c =================================================================== RCS file: /home/ncvs/src/sys/net/if_tun.c,v retrieving revision 1.152.2.2 diff -u -r1.152.2.2 if_tun.c --- if_tun.c 25 Aug 2005 05:01:20 -0000 1.152.2.2 +++ if_tun.c 1 Mar 2006 10:47:48 -0000 @@ -117,6 +117,17 @@ struct rtentry *rt); static void tunstart(struct ifnet *); +/* kqueue(2) */ +static int tun_kqfilter(struct cdev *, struct knote *); +static int tun_kqread(struct knote *, long); +static int tun_kqwrite(struct knote *, long); +static void tun_kqdetach(struct knote *); + +static struct filterops tun_read_filterops = { 1, NULL, tun_kqdetach, + tun_kqread }; +static struct filterops tun_write_filterops = { 1, NULL, tun_kqdetach, + tun_kqwrite }; + static d_open_t tunopen; static d_close_t tunclose; static d_read_t tunread; @@ -134,6 +145,7 @@ .d_ioctl = tunioctl, .d_poll = tunpoll, .d_name = TUNNAME, + .d_kqfilter = tun_kqfilter, }; static void @@ -252,6 +264,7 @@ } else mtx_unlock(&tp->tun_mtx); selwakeuppri(&tp->tun_rsel, PZERO + 1); + KNOTE(&tp->tun_rsel.si_note, 0, 0); } /* XXX: should return an error code so it can fail. */ @@ -323,6 +336,9 @@ tp->tun_flags |= TUN_OPEN; mtx_unlock(&tp->tun_mtx); ifp = TUN2IFP(tp); + + knlist_init(&tp->tun_rsel.si_note, NULL, NULL, NULL, NULL); + TUNDEBUG(ifp, "open\n"); return (0); @@ -376,6 +392,10 @@ funsetown(&tp->tun_sigio); selwakeuppri(&tp->tun_rsel, PZERO + 1); + KNOTE(&tp->tun_rsel.si_note, 0, 0); + + knlist_destroy(&tp->tun_rsel.si_note); + TUNDEBUG (ifp, "closed\n"); return (0); } @@ -862,4 +882,84 @@ splx(s); return (revents); +} + +static int +tun_kqfilter(struct cdev *dev, struct knote *kn) +{ + int s; + struct tun_softc *tp = dev->si_drv1; + struct ifnet *ifp = tp->tun_ifp; + + s = splimp(); + switch (kn->kn_filter) { + case EVFILT_READ: + TUNDEBUG(ifp, "kqfilter: EVFILT_READ, minor = %#x\n", + minor(dev)); + kn->kn_fop = &tun_read_filterops; + break; + case EVFILT_WRITE: + TUNDEBUG(ifp, "kqfilter: EVFILT_WRITE, minor = %#x\n", + minor(dev)); + kn->kn_fop = &tun_write_filterops; + break; + default: + TUNDEBUG(ifp, "kqfilter: invalid filter, minor = %#x\n", + minor(dev)); + splx(s); + return EINVAL; + break; + } + splx(s); + + kn->kn_hook = (caddr_t)dev; + knlist_add(&tp->tun_rsel.si_note, kn, 0); + + return 0; +} + +/* Return true if there is data in the interface queue. */ +static int +tun_kqread(struct knote *kn, long hint) +{ + int ret, s; + struct cdev *dev = (struct cdev *)kn->kn_hook; + struct tun_softc *tp = dev->si_drv1; + struct ifnet *ifp = tp->tun_ifp; + + s = splimp(); + if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) { + TUNDEBUG(ifp, "have data in queue. len = %d, " \ + "minor = %#x\n", ifp->if_snd.ifq_len, minor(dev)); + ret = 1; + } else { + TUNDEBUG(ifp, "waiting for data, minor = %#x\n", minor(dev)); + ret = 0; + } + splx(s); + + return ret; +} + +/* Always can write. Return the MTU in kn->data. */ +static int +tun_kqwrite(struct knote *kn, long hint) +{ + int s; + struct tun_softc *tp = ((struct cdev *)kn->kn_hook)->si_drv1; + struct ifnet *ifp = tp->tun_ifp; + + s = splimp(); + kn->kn_data = ifp->if_mtu; + splx(s); + + return 1; +} + +static void +tun_kqdetach(struct knote *kn) +{ + struct tun_softc *tp = ((struct cdev *)kn->kn_hook)->si_drv1; + + knlist_remove(&tp->tun_rsel.si_note, kn, 0); } >How-To-Repeat: Use kqueue/kevent on a file descriptor obtained from opening /dev/tunX. >Fix: I've prepared a patch to address this issue: http://innoidea.com/~vili/if_tun.diff , it cleanly applies against -CURRENT and RELENG_6_0 too. Index: if_tun.c =================================================================== RCS file: /home/ncvs/src/sys/net/if_tun.c,v retrieving revision 1.152.2.2 diff -u -r1.152.2.2 if_tun.c --- if_tun.c 25 Aug 2005 05:01:20 -0000 1.152.2.2 +++ if_tun.c 1 Mar 2006 10:47:48 -0000 @@ -117,6 +117,17 @@ struct rtentry *rt); static void tunstart(struct ifnet *); +/* kqueue(2) */ +static int tun_kqfilter(struct cdev *, struct knote *); +static int tun_kqread(struct knote *, long); +static int tun_kqwrite(struct knote *, long); +static void tun_kqdetach(struct knote *); + +static struct filterops tun_read_filterops = { 1, NULL, tun_kqdetach, + tun_kqread }; +static struct filterops tun_write_filterops = { 1, NULL, tun_kqdetach, + tun_kqwrite }; + static d_open_t tunopen; static d_close_t tunclose; static d_read_t tunread; @@ -134,6 +145,7 @@ .d_ioctl = tunioctl, .d_poll = tunpoll, .d_name = TUNNAME, + .d_kqfilter = tun_kqfilter, }; static void @@ -252,6 +264,7 @@ } else mtx_unlock(&tp->tun_mtx); selwakeuppri(&tp->tun_rsel, PZERO + 1); + KNOTE(&tp->tun_rsel.si_note, 0, 0); } /* XXX: should return an error code so it can fail. */ @@ -323,6 +336,9 @@ tp->tun_flags |= TUN_OPEN; mtx_unlock(&tp->tun_mtx); ifp = TUN2IFP(tp); + + knlist_init(&tp->tun_rsel.si_note, NULL, NULL, NULL, NULL); + TUNDEBUG(ifp, "open\n"); return (0); @@ -376,6 +392,10 @@ funsetown(&tp->tun_sigio); selwakeuppri(&tp->tun_rsel, PZERO + 1); + KNOTE(&tp->tun_rsel.si_note, 0, 0); + + knlist_destroy(&tp->tun_rsel.si_note); + TUNDEBUG (ifp, "closed\n"); return (0); } @@ -862,4 +882,84 @@ splx(s); return (revents); +} + +static int +tun_kqfilter(struct cdev *dev, struct knote *kn) +{ + int s; + struct tun_softc *tp = dev->si_drv1; + struct ifnet *ifp = tp->tun_ifp; + + s = splimp(); + switch (kn->kn_filter) { + case EVFILT_READ: + TUNDEBUG(ifp, "kqfilter: EVFILT_READ, minor = %#x\n", + minor(dev)); + kn->kn_fop = &tun_read_filterops; + break; + case EVFILT_WRITE: + TUNDEBUG(ifp, "kqfilter: EVFILT_WRITE, minor = %#x\n", + minor(dev)); + kn->kn_fop = &tun_write_filterops; + break; + default: + TUNDEBUG(ifp, "kqfilter: invalid filter, minor = %#x\n", + minor(dev)); + splx(s); + return EINVAL; + break; + } + splx(s); + + kn->kn_hook = (caddr_t)dev; + knlist_add(&tp->tun_rsel.si_note, kn, 0); + + return 0; +} + +/* Return true if there is data in the interface queue. */ +static int +tun_kqread(struct knote *kn, long hint) +{ + int ret, s; + struct cdev *dev = (struct cdev *)kn->kn_hook; + struct tun_softc *tp = dev->si_drv1; + struct ifnet *ifp = tp->tun_ifp; + + s = splimp(); + if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) { + TUNDEBUG(ifp, "have data in queue. len = %d, " \ + "minor = %#x\n", ifp->if_snd.ifq_len, minor(dev)); + ret = 1; + } else { + TUNDEBUG(ifp, "waiting for data, minor = %#x\n", minor(dev)); + ret = 0; + } + splx(s); + + return ret; +} + +/* Always can write. Return the MTU in kn->data. */ +static int +tun_kqwrite(struct knote *kn, long hint) +{ + int s; + struct tun_softc *tp = ((struct cdev *)kn->kn_hook)->si_drv1; + struct ifnet *ifp = tp->tun_ifp; + + s = splimp(); + kn->kn_data = ifp->if_mtu; + splx(s); + + return 1; +} + +static void +tun_kqdetach(struct knote *kn) +{ + struct tun_softc *tp = ((struct cdev *)kn->kn_hook)->si_drv1; + + knlist_remove(&tp->tun_rsel.si_note, kn, 0); } >Release-Note: >Audit-Trail: >Unformatted: