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