Add tap_mtx to tap_softc in order to protect per-softc variables

(tap_pid, tap_flags).  if_tap should now be entirely MPSAFE.

Committed from:			Bamboo house by ocean in Taiwan
Tropical paradise provided by:	Chia-liang Kao <clkao@clkao.org>
This commit is contained in:
Robert Watson 2004-03-17 01:09:59 +00:00
parent 456f076f01
commit 7c924a5287
2 changed files with 44 additions and 2 deletions

View File

@ -163,10 +163,13 @@ tapmodevent(mod, type, data)
*/ */
mtx_lock(&tapmtx); mtx_lock(&tapmtx);
SLIST_FOREACH(tp, &taphead, tap_next) { SLIST_FOREACH(tp, &taphead, tap_next) {
mtx_lock(&tp->tap_mtx);
if (tp->tap_flags & TAP_OPEN) { if (tp->tap_flags & TAP_OPEN) {
mtx_unlock(&tp->tap_mtx);
mtx_unlock(&tapmtx); mtx_unlock(&tapmtx);
return (EBUSY); return (EBUSY);
} }
mtx_unlock(&tp->tap_mtx);
} }
mtx_unlock(&tapmtx); mtx_unlock(&tapmtx);
@ -181,6 +184,7 @@ tapmodevent(mod, type, data)
TAPDEBUG("detaching %s\n", ifp->if_xname); TAPDEBUG("detaching %s\n", ifp->if_xname);
/* Unlocked read. */
KASSERT(!(tp->tap_flags & TAP_OPEN), KASSERT(!(tp->tap_flags & TAP_OPEN),
("%s flags is out of sync", ifp->if_xname)); ("%s flags is out of sync", ifp->if_xname));
@ -189,6 +193,7 @@ tapmodevent(mod, type, data)
ether_ifdetach(ifp); ether_ifdetach(ifp);
splx(s); splx(s);
mtx_destroy(&tp->tap_mtx);
free(tp, M_TAP); free(tp, M_TAP);
mtx_lock(&tapmtx); mtx_lock(&tapmtx);
} }
@ -269,6 +274,7 @@ tapcreate(dev)
/* allocate driver storage and create device */ /* allocate driver storage and create device */
MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 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); mtx_lock(&tapmtx);
SLIST_INSERT_HEAD(&taphead, tp, tap_next); SLIST_INSERT_HEAD(&taphead, tp, tap_next);
mtx_unlock(&tapmtx); mtx_unlock(&tapmtx);
@ -310,7 +316,9 @@ tapcreate(dev)
ether_ifattach(ifp, tp->arpcom.ac_enaddr); ether_ifattach(ifp, tp->arpcom.ac_enaddr);
splx(s); splx(s);
mtx_lock(&tp->tap_mtx);
tp->tap_flags |= TAP_INITED; tp->tap_flags |= TAP_INITED;
mtx_unlock(&tp->tap_mtx);
TAPDEBUG("interface %s is created. minor = %#x\n", TAPDEBUG("interface %s is created. minor = %#x\n",
ifp->if_xname, minor(dev)); ifp->if_xname, minor(dev));
@ -344,13 +352,16 @@ tapopen(dev, flag, mode, td)
tp = dev->si_drv1; tp = dev->si_drv1;
} }
/* Unlocked read. */
KASSERT(!(tp->tap_flags & TAP_OPEN), KASSERT(!(tp->tap_flags & TAP_OPEN),
("%s flags is out of sync", tp->tap_if.if_xname)); ("%s flags is out of sync", tp->tap_if.if_xname));
bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 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_pid = td->td_proc->p_pid;
tp->tap_flags |= TAP_OPEN; tp->tap_flags |= TAP_OPEN;
mtx_unlock(&tp->tap_mtx);
TAPDEBUG("%s is open. minor = %#x\n", TAPDEBUG("%s is open. minor = %#x\n",
tp->tap_if.if_xname, minor(dev)); 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. * 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)) { if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
mtx_unlock(&tp->tap_mtx);
s = splimp(); s = splimp();
if_down(ifp); if_down(ifp);
if (ifp->if_flags & IFF_RUNNING) { if (ifp->if_flags & IFF_RUNNING) {
/* find internet addresses and delete routes */ /* find internet addresses and delete routes */
struct ifaddr *ifa = NULL; struct ifaddr *ifa = NULL;
/* In desparate need of ifaddr locking. */
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family == AF_INET) { if (ifa->ifa_addr->sa_family == AF_INET) {
rtinit(ifa, (int)RTM_DELETE, 0); rtinit(ifa, (int)RTM_DELETE, 0);
@ -407,13 +421,16 @@ tapclose(dev, foo, bar, td)
ifp->if_flags &= ~IFF_RUNNING; ifp->if_flags &= ~IFF_RUNNING;
} }
splx(s); splx(s);
} } else
mtx_unlock(&tp->tap_mtx);
funsetown(&tp->tap_sigio); funsetown(&tp->tap_sigio);
selwakeuppri(&tp->tap_rsel, PZERO+1); selwakeuppri(&tp->tap_rsel, PZERO+1);
mtx_lock(&tp->tap_mtx);
tp->tap_flags &= ~TAP_OPEN; tp->tap_flags &= ~TAP_OPEN;
tp->tap_pid = 0; tp->tap_pid = 0;
mtx_unlock(&tp->tap_mtx);
TAPDEBUG("%s is closed. minor = %#x\n", TAPDEBUG("%s is closed. minor = %#x\n",
ifp->if_xname, minor(dev)); ifp->if_xname, minor(dev));
@ -469,10 +486,12 @@ tapifioctl(ifp, cmd, data)
s = splimp(); s = splimp();
ifs = (struct ifstat *)data; ifs = (struct ifstat *)data;
dummy = strlen(ifs->ascii); dummy = strlen(ifs->ascii);
mtx_lock(&tp->tap_mtx);
if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
snprintf(ifs->ascii + dummy, snprintf(ifs->ascii + dummy,
sizeof(ifs->ascii) - dummy, sizeof(ifs->ascii) - dummy,
"\tOpened by PID %d\n", tp->tap_pid); "\tOpened by PID %d\n", tp->tap_pid);
mtx_unlock(&tp->tap_mtx);
splx(s); splx(s);
break; break;
@ -506,10 +525,14 @@ tapifstart(ifp)
* XXX: can this do any harm because of queue overflow? * XXX: can this do any harm because of queue overflow?
*/ */
mtx_lock(&tp->tap_mtx);
if (((tp->tap_flags & TAP_VMNET) == 0) && if (((tp->tap_flags & TAP_VMNET) == 0) &&
((tp->tap_flags & TAP_READY) != TAP_READY)) { ((tp->tap_flags & TAP_READY) != TAP_READY)) {
struct mbuf *m = NULL; struct mbuf *m = NULL;
mtx_unlock(&tp->tap_mtx);
/* Unlocked read. */
TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
tp->tap_flags); tp->tap_flags);
@ -524,18 +547,23 @@ tapifstart(ifp)
return; return;
} }
mtx_unlock(&tp->tap_mtx);
s = splimp(); s = splimp();
ifp->if_flags |= IFF_OACTIVE; ifp->if_flags |= IFF_OACTIVE;
if (ifp->if_snd.ifq_len != 0) { if (ifp->if_snd.ifq_len != 0) {
mtx_lock(&tp->tap_mtx);
if (tp->tap_flags & TAP_RWAIT) { if (tp->tap_flags & TAP_RWAIT) {
tp->tap_flags &= ~TAP_RWAIT; tp->tap_flags &= ~TAP_RWAIT;
wakeup(tp); 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); pgsigio(&tp->tap_sigio, SIGIO, 0);
} else
mtx_unlock(&tp->tap_mtx);
selwakeuppri(&tp->tap_rsel, PZERO+1); selwakeuppri(&tp->tap_rsel, PZERO+1);
ifp->if_opackets ++; /* obytes are counted in ether_output */ ifp->if_opackets ++; /* obytes are counted in ether_output */
@ -595,10 +623,12 @@ tapioctl(dev, cmd, data, flag, td)
case FIOASYNC: case FIOASYNC:
s = splimp(); s = splimp();
mtx_lock(&tp->tap_mtx);
if (*(int *)data) if (*(int *)data)
tp->tap_flags |= TAP_ASYNC; tp->tap_flags |= TAP_ASYNC;
else else
tp->tap_flags &= ~TAP_ASYNC; tp->tap_flags &= ~TAP_ASYNC;
mtx_unlock(&tp->tap_mtx);
splx(s); splx(s);
break; break;
@ -682,7 +712,11 @@ tapread(dev, uio, flag)
TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev)); TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev));
mtx_lock(&tp->tap_mtx);
if ((tp->tap_flags & TAP_READY) != TAP_READY) { 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", TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
ifp->if_xname, minor(dev), tp->tap_flags); ifp->if_xname, minor(dev), tp->tap_flags);
@ -690,6 +724,7 @@ tapread(dev, uio, flag)
} }
tp->tap_flags &= ~TAP_RWAIT; tp->tap_flags &= ~TAP_RWAIT;
mtx_unlock(&tp->tap_mtx);
/* sleep until we get a packet */ /* sleep until we get a packet */
do { do {
@ -701,7 +736,9 @@ tapread(dev, uio, flag)
if (flag & IO_NDELAY) if (flag & IO_NDELAY)
return (EWOULDBLOCK); return (EWOULDBLOCK);
mtx_lock(&tp->tap_mtx);
tp->tap_flags |= TAP_RWAIT; tp->tap_flags |= TAP_RWAIT;
mtx_unlock(&tp->tap_mtx);
error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0);
if (error) if (error)
return (error); return (error);

View File

@ -41,6 +41,10 @@
#ifndef _NET_IF_TAPVAR_H_ #ifndef _NET_IF_TAPVAR_H_
#define _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 tap_softc {
struct arpcom arpcom; /* ethernet common data */ struct arpcom arpcom; /* ethernet common data */
#define tap_if arpcom.ac_if #define tap_if arpcom.ac_if
@ -60,6 +64,7 @@ struct tap_softc {
SLIST_ENTRY(tap_softc) tap_next; /* next device in chain */ SLIST_ENTRY(tap_softc) tap_next; /* next device in chain */
dev_t tap_dev; dev_t tap_dev;
struct mtx tap_mtx; /* per-softc mutex */
}; };
#endif /* !_NET_IF_TAPVAR_H_ */ #endif /* !_NET_IF_TAPVAR_H_ */