From owner-freebsd-bugs@FreeBSD.ORG Mon Feb 27 11:40:07 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 D2C4A16A420 for ; Mon, 27 Feb 2006 11:40:07 +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 F03C643D48 for ; Mon, 27 Feb 2006 11:40: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 k1RBe4Ou053346 for ; Mon, 27 Feb 2006 11:40:04 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.4/8.13.4/Submit) id k1RBe45d053345; Mon, 27 Feb 2006 11:40:04 GMT (envelope-from gnats) Resent-Date: Mon, 27 Feb 2006 11:40:04 GMT Resent-Message-Id: <200602271140.k1RBe45d053345@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 9CA3516A422 for ; Mon, 27 Feb 2006 11:31:06 +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 62AEE43D4C for ; Mon, 27 Feb 2006 11:31:06 +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 k1RBV5Wu003557 for ; Mon, 27 Feb 2006 11:31:05 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.13.1/8.13.1/Submit) id k1RBV53Q003556; Mon, 27 Feb 2006 11:31:05 GMT (envelope-from nobody) Message-Id: <200602271131.k1RBV53Q003556@www.freebsd.org> Date: Mon, 27 Feb 2006 11:31:05 GMT From: Vilmos Nebehaj To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-2.3 Cc: Subject: kern/93897: if_tap 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: Mon, 27 Feb 2006 11:40:08 -0000 >Number: 93897 >Category: kern >Synopsis: if_tap 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: Mon Feb 27 11:40:04 GMT 2006 >Closed-Date: >Last-Modified: >Originator: Vilmos Nebehaj >Release: FreeBSD 6.0 >Organization: >Environment: oszoo# uname -a FreeBSD oszoo.oszoo 6.0-RELEASE FreeBSD 6.0-RELEASE #0: Thu Nov 3 09:36:13 UTC 2005 root@x64.samsco.home:/usr/obj/usr/src/sys/GENERIC i386 >Description: Kqueue(2) doesn't work on if_tap devices, so applications have to use select or poll. NetBSD and OpenBSD have had the necessary kqueue bits for quite a while, so it would be desirable for FreeBSD to do the same. >How-To-Repeat: Use kqueue/kevent on a file descriptor obtained from opening /dev/tapX. >Fix: I've prepared a patch. It cleanly applies against -CURRENT and RELENG_6_0 too. It can be fetched from http://innoidea.com/~vili/if_tap.diff Index: if_tap.c =================================================================== RCS file: /home/ncvs/src/sys/net/if_tap.c,v retrieving revision 1.58 diff -u -r1.58 if_tap.c --- if_tap.c 11 Nov 2005 16:04:48 -0000 1.58 +++ if_tap.c 27 Feb 2006 10:39:38 -0000 @@ -99,6 +99,17 @@ static d_ioctl_t tapioctl; static d_poll_t tappoll; +/* kqueue(2) */ +static int tap_kqfilter(struct cdev *, struct knote *); +static int tap_kqread(struct knote *, long); +static int tap_kqwrite(struct knote *, long); +static void tap_kqdetach(struct knote *); + +static struct filterops tap_read_filterops = { 1, NULL, tap_kqdetach, + tap_kqread }; +static struct filterops tap_write_filterops = { 1, NULL, tap_kqdetach, + tap_kqwrite }; + static struct cdevsw tap_cdevsw = { .d_version = D_VERSION, .d_flags = D_PSEUDO | D_NEEDGIANT, @@ -109,6 +120,7 @@ .d_ioctl = tapioctl, .d_poll = tappoll, .d_name = CDEV_NAME, + .d_kqfilter = tap_kqfilter, }; /* @@ -397,6 +409,8 @@ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; splx(s); + knlist_init(&tp->tap_rsel.si_note, NULL, NULL, NULL, NULL); + TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev)); return (0); @@ -446,12 +460,15 @@ funsetown(&tp->tap_sigio); selwakeuppri(&tp->tap_rsel, PZERO+1); + KNOTE(&tp->tap_rsel.si_note, 0, 0); mtx_lock(&tp->tap_mtx); tp->tap_flags &= ~TAP_OPEN; tp->tap_pid = 0; mtx_unlock(&tp->tap_mtx); + knlist_destroy(&tp->tap_rsel.si_note); + TAPDEBUG("%s is closed. minor = %#x\n", ifp->if_xname, minor(dev)); @@ -586,6 +603,7 @@ mtx_unlock(&tp->tap_mtx); selwakeuppri(&tp->tap_rsel, PZERO+1); + KNOTE(&tp->tap_rsel.si_note, 0, 0); ifp->if_opackets ++; /* obytes are counted in ether_output */ } @@ -878,3 +896,78 @@ splx(s); return (revents); } /* tappoll */ + +static int +tap_kqfilter(struct cdev *dev, struct knote *kn) +{ + struct tap_softc *tp = dev->si_drv1; + struct ifnet *ifp = tp->tap_ifp; + + switch (kn->kn_filter) { + case EVFILT_READ: + TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n", + ifp->if_xname, minor(dev)); + kn->kn_fop = &tap_read_filterops; + break; + case EVFILT_WRITE: + TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n", + ifp->if_xname, minor(dev)); + kn->kn_fop = &tap_write_filterops; + break; + default: + TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n", + ifp->if_xname, minor(dev)); + return EINVAL; + break; + } + + kn->kn_hook = (caddr_t)dev; + knlist_add(&tp->tap_rsel.si_note, kn, 0); + + return 0; +} + +/* Return true if there is data in the interface queue. */ +static int +tap_kqread(struct knote *kn, long hint) +{ + int ret, s; + struct cdev *dev = (struct cdev *)kn->kn_hook; + struct tap_softc *tp = dev->si_drv1; + struct ifnet *ifp = tp->tap_ifp; + + s = splimp(); + if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) { + TAPDEBUG("%s have data in queue. len = %d, " \ + "minor = %#x\n", ifp->if_xname, + ifp->if_snd.ifq_len, minor(dev)); + ret = 1; + } else { + TAPDEBUG("%s waiting for data, minor = %#x\n", + ifp->if_xname, minor(dev)); + ret = 0; + } + splx(s); + + return ret; +} + +/* Always can write. Return the MTU in kn->data. */ +static int +tap_kqwrite(struct knote *kn, long hint) +{ + struct tap_softc *tp = ((struct cdev *)kn->kn_hook)->si_drv1; + struct ifnet *ifp = tp->tap_ifp; + + kn->kn_data = ifp->if_mtu; + + return 1; +} + +static void +tap_kqdetach(struct knote *kn) +{ + struct tap_softc *tp = ((struct cdev *)kn->kn_hook)->si_drv1; + + knlist_remove(&tp->tap_rsel.si_note, kn, 0); +} >Release-Note: >Audit-Trail: >Unformatted: