summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/net/if_tap.c41
-rw-r--r--sys/net/if_tapvar.h5
2 files changed, 44 insertions, 2 deletions
diff --git a/sys/net/if_tap.c b/sys/net/if_tap.c
index 503741e..3daf8ec 100644
--- a/sys/net/if_tap.c
+++ b/sys/net/if_tap.c
@@ -163,10 +163,13 @@ tapmodevent(mod, type, data)
*/
mtx_lock(&tapmtx);
SLIST_FOREACH(tp, &taphead, tap_next) {
+ mtx_lock(&tp->tap_mtx);
if (tp->tap_flags & TAP_OPEN) {
+ mtx_unlock(&tp->tap_mtx);
mtx_unlock(&tapmtx);
return (EBUSY);
}
+ mtx_unlock(&tp->tap_mtx);
}
mtx_unlock(&tapmtx);
@@ -181,6 +184,7 @@ tapmodevent(mod, type, data)
TAPDEBUG("detaching %s\n", ifp->if_xname);
+ /* Unlocked read. */
KASSERT(!(tp->tap_flags & TAP_OPEN),
("%s flags is out of sync", ifp->if_xname));
@@ -189,6 +193,7 @@ tapmodevent(mod, type, data)
ether_ifdetach(ifp);
splx(s);
+ mtx_destroy(&tp->tap_mtx);
free(tp, M_TAP);
mtx_lock(&tapmtx);
}
@@ -269,6 +274,7 @@ tapcreate(dev)
/* allocate driver storage and create device */
MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
+ mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF);
mtx_lock(&tapmtx);
SLIST_INSERT_HEAD(&taphead, tp, tap_next);
mtx_unlock(&tapmtx);
@@ -310,7 +316,9 @@ tapcreate(dev)
ether_ifattach(ifp, tp->arpcom.ac_enaddr);
splx(s);
+ mtx_lock(&tp->tap_mtx);
tp->tap_flags |= TAP_INITED;
+ mtx_unlock(&tp->tap_mtx);
TAPDEBUG("interface %s is created. minor = %#x\n",
ifp->if_xname, minor(dev));
@@ -344,13 +352,16 @@ tapopen(dev, flag, mode, td)
tp = dev->si_drv1;
}
+ /* Unlocked read. */
KASSERT(!(tp->tap_flags & TAP_OPEN),
("%s flags is out of sync", tp->tap_if.if_xname));
bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
+ mtx_lock(&tp->tap_mtx);
tp->tap_pid = td->td_proc->p_pid;
tp->tap_flags |= TAP_OPEN;
+ mtx_unlock(&tp->tap_mtx);
TAPDEBUG("%s is open. minor = %#x\n",
tp->tap_if.if_xname, minor(dev));
@@ -383,13 +394,16 @@ tapclose(dev, foo, bar, td)
* interface, if we are in VMnet mode. just close the device.
*/
+ mtx_lock(&tp->tap_mtx);
if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
+ mtx_unlock(&tp->tap_mtx);
s = splimp();
if_down(ifp);
if (ifp->if_flags & IFF_RUNNING) {
/* find internet addresses and delete routes */
struct ifaddr *ifa = NULL;
+ /* In desparate need of ifaddr locking. */
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family == AF_INET) {
rtinit(ifa, (int)RTM_DELETE, 0);
@@ -407,13 +421,16 @@ tapclose(dev, foo, bar, td)
ifp->if_flags &= ~IFF_RUNNING;
}
splx(s);
- }
+ } else
+ mtx_unlock(&tp->tap_mtx);
funsetown(&tp->tap_sigio);
selwakeuppri(&tp->tap_rsel, PZERO+1);
+ mtx_lock(&tp->tap_mtx);
tp->tap_flags &= ~TAP_OPEN;
tp->tap_pid = 0;
+ mtx_unlock(&tp->tap_mtx);
TAPDEBUG("%s is closed. minor = %#x\n",
ifp->if_xname, minor(dev));
@@ -469,10 +486,12 @@ tapifioctl(ifp, cmd, data)
s = splimp();
ifs = (struct ifstat *)data;
dummy = strlen(ifs->ascii);
+ mtx_lock(&tp->tap_mtx);
if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
snprintf(ifs->ascii + dummy,
sizeof(ifs->ascii) - dummy,
"\tOpened by PID %d\n", tp->tap_pid);
+ mtx_unlock(&tp->tap_mtx);
splx(s);
break;
@@ -506,10 +525,14 @@ tapifstart(ifp)
* XXX: can this do any harm because of queue overflow?
*/
+ mtx_lock(&tp->tap_mtx);
if (((tp->tap_flags & TAP_VMNET) == 0) &&
((tp->tap_flags & TAP_READY) != TAP_READY)) {
struct mbuf *m = NULL;
+ mtx_unlock(&tp->tap_mtx);
+
+ /* Unlocked read. */
TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
tp->tap_flags);
@@ -524,18 +547,23 @@ tapifstart(ifp)
return;
}
+ mtx_unlock(&tp->tap_mtx);
s = splimp();
ifp->if_flags |= IFF_OACTIVE;
if (ifp->if_snd.ifq_len != 0) {
+ mtx_lock(&tp->tap_mtx);
if (tp->tap_flags & TAP_RWAIT) {
tp->tap_flags &= ~TAP_RWAIT;
wakeup(tp);
}
- if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL))
+ if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) {
+ mtx_unlock(&tp->tap_mtx);
pgsigio(&tp->tap_sigio, SIGIO, 0);
+ } else
+ mtx_unlock(&tp->tap_mtx);
selwakeuppri(&tp->tap_rsel, PZERO+1);
ifp->if_opackets ++; /* obytes are counted in ether_output */
@@ -595,10 +623,12 @@ tapioctl(dev, cmd, data, flag, td)
case FIOASYNC:
s = splimp();
+ mtx_lock(&tp->tap_mtx);
if (*(int *)data)
tp->tap_flags |= TAP_ASYNC;
else
tp->tap_flags &= ~TAP_ASYNC;
+ mtx_unlock(&tp->tap_mtx);
splx(s);
break;
@@ -682,7 +712,11 @@ tapread(dev, uio, flag)
TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev));
+ mtx_lock(&tp->tap_mtx);
if ((tp->tap_flags & TAP_READY) != TAP_READY) {
+ mtx_unlock(&tp->tap_mtx);
+
+ /* Unlocked read. */
TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
ifp->if_xname, minor(dev), tp->tap_flags);
@@ -690,6 +724,7 @@ tapread(dev, uio, flag)
}
tp->tap_flags &= ~TAP_RWAIT;
+ mtx_unlock(&tp->tap_mtx);
/* sleep until we get a packet */
do {
@@ -701,7 +736,9 @@ tapread(dev, uio, flag)
if (flag & IO_NDELAY)
return (EWOULDBLOCK);
+ mtx_lock(&tp->tap_mtx);
tp->tap_flags |= TAP_RWAIT;
+ mtx_unlock(&tp->tap_mtx);
error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0);
if (error)
return (error);
diff --git a/sys/net/if_tapvar.h b/sys/net/if_tapvar.h
index 5b7312f..acd4528 100644
--- a/sys/net/if_tapvar.h
+++ b/sys/net/if_tapvar.h
@@ -41,6 +41,10 @@
#ifndef _NET_IF_TAPVAR_H_
#define _NET_IF_TAPVAR_H_
+/*
+ * tap_mtx locks tap_flags, tap_pid. tap_next locked with global tapmtx.
+ * Other fields locked by owning subsystems.
+ */
struct tap_softc {
struct arpcom arpcom; /* ethernet common data */
#define tap_if arpcom.ac_if
@@ -60,6 +64,7 @@ struct tap_softc {
SLIST_ENTRY(tap_softc) tap_next; /* next device in chain */
dev_t tap_dev;
+ struct mtx tap_mtx; /* per-softc mutex */
};
#endif /* !_NET_IF_TAPVAR_H_ */
OpenPOWER on IntegriCloud