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:
parent
456f076f01
commit
7c924a5287
@ -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);
|
||||||
|
@ -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_ */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user