Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/net Make tap(4) MP-safe.



details:   https://anonhg.NetBSD.org/src/rev/66c730644032
branches:  trunk
changeset: 828134:66c730644032
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Wed Nov 29 19:21:44 2017 +0000

description:
Make tap(4) MP-safe.

diffstat:

 sys/net/if_tap.c |  100 ++++++++++++++++++++----------------------------------
 1 files changed, 38 insertions(+), 62 deletions(-)

diffs (282 lines):

diff -r 99f5c533d0a8 -r 66c730644032 sys/net/if_tap.c
--- a/sys/net/if_tap.c  Wed Nov 29 18:15:53 2017 +0000
+++ b/sys/net/if_tap.c  Wed Nov 29 19:21:44 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_tap.c,v 1.101 2017/10/30 16:01:19 ozaki-r Exp $     */
+/*     $NetBSD: if_tap.c,v 1.102 2017/11/29 19:21:44 jmcneill Exp $    */
 
 /*
  *  Copyright (c) 2003, 2004, 2008, 2009 The NetBSD Foundation.
@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_tap.c,v 1.101 2017/10/30 16:01:19 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_tap.c,v 1.102 2017/11/29 19:21:44 jmcneill Exp $");
 
 #if defined(_KERNEL_OPT)
 
@@ -54,6 +54,7 @@
 #include <sys/kmem.h>
 #include <sys/module.h>
 #include <sys/mutex.h>
+#include <sys/condvar.h>
 #include <sys/poll.h>
 #include <sys/proc.h>
 #include <sys/select.h>
@@ -109,8 +110,8 @@
 #define TAP_GOING      0x00000008      /* interface is being destroyed */
        struct selinfo  sc_rsel;
        pid_t           sc_pgid; /* For async. IO */
-       kmutex_t        sc_rdlock;
-       kmutex_t        sc_kqlock;
+       kmutex_t        sc_lock;
+       kcondvar_t      sc_cv;
        void            *sc_sih;
        struct timespec sc_atime;
        struct timespec sc_mtime;
@@ -182,7 +183,7 @@
        .d_mmap = nommap,
        .d_kqfilter = tap_cdev_kqfilter,
        .d_discard = nodiscard,
-       .d_flag = D_OTHER
+       .d_flag = D_OTHER | D_MPSAFE
 };
 
 #define TAP_CLONER     0xfffff         /* Maximal minor value */
@@ -315,22 +316,8 @@
        sc->sc_flags = 0;
        selinit(&sc->sc_rsel);
 
-       /*
-        * Initialize the two locks for the device.
-        *
-        * We need a lock here because even though the tap device can be
-        * opened only once, the file descriptor might be passed to another
-        * process, say a fork(2)ed child.
-        *
-        * The Giant saves us from most of the hassle, but since the read
-        * operation can sleep, we don't want two processes to wake up at
-        * the same moment and both try and dequeue a single packet.
-        *
-        * The queue for event listeners (used by kqueue(9), see below) has
-        * to be protected too, so use a spin lock.
-        */
-       mutex_init(&sc->sc_rdlock, MUTEX_DEFAULT, IPL_NONE);
-       mutex_init(&sc->sc_kqlock, MUTEX_DEFAULT, IPL_VM);
+       cv_init(&sc->sc_cv, "tapread");
+       mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NET);
 
        if (!pmf_device_register(self, NULL, NULL))
                aprint_error_dev(self, "couldn't establish power handler\n");
@@ -385,12 +372,12 @@
                aprint_error_dev(self, "if_initialize failed(%d)\n", error);
                ifmedia_removeall(&sc->sc_im);
                pmf_device_deregister(self);
-               mutex_destroy(&sc->sc_rdlock);
-               mutex_destroy(&sc->sc_kqlock);
+               mutex_destroy(&sc->sc_lock);
                seldestroy(&sc->sc_rsel);
 
                return; /* Error */
        }
+       ifp->if_percpuq = if_percpuq_create(ifp);
        ether_ifattach(ifp, enaddr);
        if_register(ifp);
 
@@ -428,13 +415,10 @@
        struct tap_softc *sc = device_private(self);
        struct ifnet *ifp = &sc->sc_ec.ec_if;
        int error;
-       int s;
 
        sc->sc_flags |= TAP_GOING;
-       s = splnet();
        tap_stop(ifp, 1);
        if_down(ifp);
-       splx(s);
 
        if (sc->sc_sih != NULL) {
                softint_disestablish(sc->sc_sih);
@@ -454,8 +438,8 @@
        if_detach(ifp);
        ifmedia_removeall(&sc->sc_im);
        seldestroy(&sc->sc_rsel);
-       mutex_destroy(&sc->sc_rdlock);
-       mutex_destroy(&sc->sc_kqlock);
+       mutex_destroy(&sc->sc_lock);
+       cv_destroy(&sc->sc_cv);
 
        pmf_device_deregister(self);
 
@@ -516,12 +500,13 @@
        struct tap_softc *sc = (struct tap_softc *)ifp->if_softc;
        struct mbuf *m0;
 
+       mutex_enter(&sc->sc_lock);
        if ((sc->sc_flags & TAP_INUSE) == 0) {
                /* Simply drop packets */
                for(;;) {
                        IFQ_DEQUEUE(&ifp->if_snd, m0);
                        if (m0 == NULL)
-                               return;
+                               goto done;
 
                        ifp->if_opackets++;
                        bpf_mtap(ifp, m0);
@@ -530,11 +515,13 @@
                }
        } else if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
                ifp->if_flags |= IFF_OACTIVE;
-               wakeup(sc);
+               cv_broadcast(&sc->sc_cv);
                selnotify(&sc->sc_rsel, 0, 1);
                if (sc->sc_flags & TAP_ASYNCIO)
                        softint_schedule(sc->sc_sih);
        }
+done:
+       mutex_exit(&sc->sc_lock);
 }
 
 static void
@@ -645,11 +632,13 @@
 {
        struct tap_softc *sc = (struct tap_softc *)ifp->if_softc;
 
+       mutex_enter(&sc->sc_lock);
        ifp->if_flags &= ~IFF_RUNNING;
-       wakeup(sc);
+       cv_broadcast(&sc->sc_cv);
        selnotify(&sc->sc_rsel, 0, 1);
        if (sc->sc_flags & TAP_ASYNCIO)
                softint_schedule(sc->sc_sih);
+       mutex_exit(&sc->sc_lock);
 }
 
 /*
@@ -931,7 +920,7 @@
        struct tap_softc *sc = device_lookup_private(&tap_cd, unit);
        struct ifnet *ifp;
        struct mbuf *m, *n;
-       int error = 0, s;
+       int error = 0;
 
        if (sc == NULL)
                return ENXIO;
@@ -946,43 +935,34 @@
         * In the TAP_NBIO case, we have to make sure we won't be sleeping
         */
        if ((sc->sc_flags & TAP_NBIO) != 0) {
-               if (!mutex_tryenter(&sc->sc_rdlock))
+               if (!mutex_tryenter(&sc->sc_lock))
                        return EWOULDBLOCK;
        } else {
-               mutex_enter(&sc->sc_rdlock);
+               mutex_enter(&sc->sc_lock);
        }
 
-       s = splnet();
        if (IFQ_IS_EMPTY(&ifp->if_snd)) {
                ifp->if_flags &= ~IFF_OACTIVE;
-               /*
-                * We must release the lock before sleeping, and re-acquire it
-                * after.
-                */
-               mutex_exit(&sc->sc_rdlock);
                if (sc->sc_flags & TAP_NBIO)
                        error = EWOULDBLOCK;
                else
-                       error = tsleep(sc, PSOCK|PCATCH, "tap", 0);
-               splx(s);
+                       error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock);
 
-               if (error != 0)
+               if (error != 0) {
+                       mutex_exit(&sc->sc_lock);
                        return error;
+               }
                /* The device might have been downed */
-               if ((ifp->if_flags & IFF_UP) == 0)
+               if ((ifp->if_flags & IFF_UP) == 0) {
+                       mutex_exit(&sc->sc_lock);
                        return EHOSTDOWN;
-               if ((sc->sc_flags & TAP_NBIO)) {
-                       if (!mutex_tryenter(&sc->sc_rdlock))
-                               return EWOULDBLOCK;
-               } else {
-                       mutex_enter(&sc->sc_rdlock);
                }
-               s = splnet();
        }
 
        IFQ_DEQUEUE(&ifp->if_snd, m);
+       mutex_exit(&sc->sc_lock);
+
        ifp->if_flags &= ~IFF_OACTIVE;
-       splx(s);
        if (m == NULL) {
                error = 0;
                goto out;
@@ -1004,7 +984,6 @@
                m_freem(m);
 
 out:
-       mutex_exit(&sc->sc_rdlock);
        return error;
 }
 
@@ -1061,7 +1040,6 @@
        struct ifnet *ifp;
        struct mbuf *m, **mp;
        int error = 0;
-       int s;
 
        if (sc == NULL)
                return ENXIO;
@@ -1098,9 +1076,7 @@
 
        m_set_rcvif(m, ifp);
 
-       s = splnet();
-       if_input(ifp, m);
-       splx(s);
+       if_percpuq_enqueue(ifp->if_percpuq, m);
 
        return 0;
 }
@@ -1221,9 +1197,9 @@
                if (m != NULL)
                        revents |= events & (POLLIN|POLLRDNORM);
                else {
-                       mutex_spin_enter(&sc->sc_kqlock);
+                       mutex_spin_enter(&sc->sc_lock);
                        selrecord(l, &sc->sc_rsel);
-                       mutex_spin_exit(&sc->sc_kqlock);
+                       mutex_spin_exit(&sc->sc_lock);
                }
                splx(s);
        }
@@ -1272,9 +1248,9 @@
        }
 
        kn->kn_hook = sc;
-       mutex_spin_enter(&sc->sc_kqlock);
+       mutex_spin_enter(&sc->sc_lock);
        SLIST_INSERT_HEAD(&sc->sc_rsel.sel_klist, kn, kn_selnext);
-       mutex_spin_exit(&sc->sc_kqlock);
+       mutex_spin_exit(&sc->sc_lock);
        KERNEL_UNLOCK_ONE(NULL);
        return 0;
 }
@@ -1285,9 +1261,9 @@
        struct tap_softc *sc = (struct tap_softc *)kn->kn_hook;
 
        KERNEL_LOCK(1, NULL);
-       mutex_spin_enter(&sc->sc_kqlock);
+       mutex_spin_enter(&sc->sc_lock);
        SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
-       mutex_spin_exit(&sc->sc_kqlock);
+       mutex_spin_exit(&sc->sc_lock);
        KERNEL_UNLOCK_ONE(NULL);
 }
 



Home | Main Index | Thread Index | Old Index