Date: Wed, 6 Feb 2019 09:38:44 +0000 (UTC) From: Vincenzo Maffione <vmaffione@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r343831 - stable/11/sys/dev/netmap Message-ID: <201902060938.x169ciks035618@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: vmaffione Date: Wed Feb 6 09:38:44 2019 New Revision: 343831 URL: https://svnweb.freebsd.org/changeset/base/343831 Log: MFC r343344 netmap: fix knote() argument to match the mutex state The nm_os_selwakeup function needs to call knote() to wake up kqueue(9) users. However, this function can be called from different code paths, with different lock requirements. This patch fixes the knote() call argument to match the relavant lock state. Also, comments have been updated to reflect current code. PR: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=219846 Reported by: Aleksandr Fedorov <aleksandr.fedorov@itglobal.com> Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D18876 Modified: stable/11/sys/dev/netmap/netmap.c stable/11/sys/dev/netmap/netmap_freebsd.c stable/11/sys/dev/netmap/netmap_kern.h Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/dev/netmap/netmap.c ============================================================================== --- stable/11/sys/dev/netmap/netmap.c Wed Feb 6 09:23:39 2019 (r343830) +++ stable/11/sys/dev/netmap/netmap.c Wed Feb 6 09:38:44 2019 (r343831) @@ -2532,7 +2532,6 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c } nifp = priv->np_nifp; - priv->np_td = td; /* for debugging purposes */ /* return the offset of the netmap_if object */ req->nr_rx_rings = na->num_rx_rings; @@ -3208,8 +3207,8 @@ nmreq_checkoptions(struct nmreq_header *hdr) * * Can be called for one or more queues. * Return true the event mask corresponding to ready events. - * If there are no ready events, do a selrecord on either individual - * selinfo or on the global one. + * If there are no ready events (and 'sr' is not NULL), do a + * selrecord on either individual selinfo or on the global one. * Device-dependent parts (locking and sync of tx/rx rings) * are done through callbacks. * Modified: stable/11/sys/dev/netmap/netmap_freebsd.c ============================================================================== --- stable/11/sys/dev/netmap/netmap_freebsd.c Wed Feb 6 09:23:39 2019 (r343830) +++ stable/11/sys/dev/netmap/netmap_freebsd.c Wed Feb 6 09:38:44 2019 (r343831) @@ -83,7 +83,7 @@ void nm_os_selinfo_uninit(NM_SELINFO_T *si) { /* XXX kqueue(9) needed; these will mirror knlist_init. */ - knlist_delete(&si->si.si_note, curthread, 0 /* not locked */ ); + knlist_delete(&si->si.si_note, curthread, /*islocked=*/0); knlist_destroy(&si->si.si_note); /* now we don't need the mutex anymore */ mtx_destroy(&si->m); @@ -1292,21 +1292,21 @@ nm_os_kctx_destroy(struct nm_kctx *nmk) /******************** kqueue support ****************/ /* - * nm_os_selwakeup also needs to issue a KNOTE_UNLOCKED. - * We use a non-zero argument to distinguish the call from the one - * in kevent_scan() which instead also needs to run netmap_poll(). - * The knote uses a global mutex for the time being. We might - * try to reuse the one in the si, but it is not allocated - * permanently so it might be a bit tricky. + * In addition to calling selwakeuppri(), nm_os_selwakeup() also + * needs to call KNOTE to wake up kqueue listeners. + * We use a non-zero 'hint' argument to inform the netmap_knrw() + * function that it is being called from 'nm_os_selwakeup'; this + * is necessary because when netmap_knrw() is called by the kevent + * subsystem (i.e. kevent_scan()) we also need to call netmap_poll(). + * The knote uses a private mutex associated to the 'si' (see struct + * selinfo, struct nm_selinfo, and nm_os_selinfo_init). * - * The *kqfilter function registers one or another f_event - * depending on read or write mode. - * In the call to f_event() td_fpop is NULL so any child function - * calling devfs_get_cdevpriv() would fail - and we need it in - * netmap_poll(). As a workaround we store priv into kn->kn_hook - * and pass it as first argument to netmap_poll(), which then - * uses the failure to tell that we are called from f_event() - * and do not need the selrecord(). + * The netmap_kqfilter() function registers one or another f_event + * depending on read or write mode. A pointer to the struct + * 'netmap_priv_d' is stored into kn->kn_hook, so that it can later + * be passed to netmap_poll(). We pass NULL as a third argument to + * netmap_poll(), so that the latter only runs the txsync/rxsync + * (if necessary), and skips the nm_os_selrecord() calls. */ @@ -1314,12 +1314,13 @@ void nm_os_selwakeup(struct nm_selinfo *si) { if (netmap_verbose) - D("on knote %p", &si->si.si_note); + nm_prinf("on knote %p", &si->si.si_note); selwakeuppri(&si->si, PI_NET); - /* use a non-zero hint to tell the notification from the - * call done in kqueue_scan() which uses 0 + /* We use a non-zero hint to distinguish this notification call + * from the call done in kqueue_scan(), which uses hint=0. */ - KNOTE_UNLOCKED(&si->si.si_note, 0x100 /* notification */); + KNOTE(&si->si.si_note, /*hint=*/0x100, + mtx_owned(&si->m) ? KNF_LISTLOCKED : 0); } void @@ -1335,7 +1336,7 @@ netmap_knrdetach(struct knote *kn) struct selinfo *si = &priv->np_si[NR_RX]->si; D("remove selinfo %p", si); - knlist_remove(&si->si_note, kn, 0); + knlist_remove(&si->si_note, kn, /*islocked=*/0); } static void @@ -1345,14 +1346,15 @@ netmap_knwdetach(struct knote *kn) struct selinfo *si = &priv->np_si[NR_TX]->si; D("remove selinfo %p", si); - knlist_remove(&si->si_note, kn, 0); + knlist_remove(&si->si_note, kn, /*islocked=*/0); } /* - * callback from notifies (generated externally) and our - * calls to kevent(). The former we just return 1 (ready) - * since we do not know better. - * In the latter we call netmap_poll and return 0/1 accordingly. + * Callback triggered by netmap notifications (see netmap_notify()), + * and by the application calling kevent(). In the former case we + * just return 1 (events ready), since we are not able to do better. + * In the latter case we use netmap_poll() to see which events are + * ready. */ static int netmap_knrw(struct knote *kn, long hint, int events) @@ -1361,21 +1363,17 @@ netmap_knrw(struct knote *kn, long hint, int events) int revents; if (hint != 0) { - ND(5, "call from notify"); - return 1; /* assume we are ready */ - } - priv = kn->kn_hook; - /* the notification may come from an external thread, - * in which case we do not want to run the netmap_poll - * This should be filtered above, but check just in case. - */ - if (curthread != priv->np_td) { /* should not happen */ - RD(5, "curthread changed %p %p", curthread, priv->np_td); + /* Called from netmap_notify(), typically from a + * thread different from the one issuing kevent(). + * Assume we are ready. */ return 1; - } else { - revents = netmap_poll(priv, events, NULL); - return (events & revents) ? 1 : 0; } + + /* Called from kevent(). */ + priv = kn->kn_hook; + revents = netmap_poll(priv, events, /*thread=*/NULL); + + return (events & revents) ? 1 : 0; } static int @@ -1406,7 +1404,7 @@ static struct filterops netmap_wfiltops = { /* * This is called when a thread invokes kevent() to record * a change in the configuration of the kqueue(). - * The 'priv' should be the same as in the netmap device. + * The 'priv' is the one associated to the open netmap device. */ static int netmap_kqfilter(struct cdev *dev, struct knote *kn) @@ -1433,16 +1431,11 @@ netmap_kqfilter(struct cdev *dev, struct knote *kn) } /* the si is indicated in the priv */ si = priv->np_si[(ev == EVFILT_WRITE) ? NR_TX : NR_RX]; - // XXX lock(priv) ? kn->kn_fop = (ev == EVFILT_WRITE) ? &netmap_wfiltops : &netmap_rfiltops; kn->kn_hook = priv; - knlist_add(&si->si.si_note, kn, 0); - // XXX unlock(priv) - ND("register %p %s td %p priv %p kn %p np_nifp %p kn_fp/fpop %s", - na, na->ifp->if_xname, curthread, priv, kn, - priv->np_nifp, - kn->kn_fp == curthread->td_fpop ? "match" : "MISMATCH"); + knlist_add(&si->si.si_note, kn, /*islocked=*/0); + return 0; } Modified: stable/11/sys/dev/netmap/netmap_kern.h ============================================================================== --- stable/11/sys/dev/netmap/netmap_kern.h Wed Feb 6 09:23:39 2019 (r343830) +++ stable/11/sys/dev/netmap/netmap_kern.h Wed Feb 6 09:38:44 2019 (r343831) @@ -1944,7 +1944,6 @@ struct netmap_priv_d { * (N entries). */ struct nm_csb_ktoa *np_csb_ktoa_base; - struct thread *np_td; /* kqueue, just debugging */ #ifdef linux struct file *np_filp; /* used by sync kloop */ #endif /* linux */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201902060938.x169ciks035618>