diff options
author | ume <ume@FreeBSD.org> | 2003-10-24 16:57:59 +0000 |
---|---|---|
committer | ume <ume@FreeBSD.org> | 2003-10-24 16:57:59 +0000 |
commit | eae980f878292d49d725e3ef2b1b3b15c2914013 (patch) | |
tree | 750fae5cf23a0f412dffeec3d6ebb79f018f0334 | |
parent | b220e7e690bce5c495774572990e4de021ab2598 (diff) | |
download | FreeBSD-src-eae980f878292d49d725e3ef2b1b3b15c2914013.zip FreeBSD-src-eae980f878292d49d725e3ef2b1b3b15c2914013.tar.gz |
Since dp->dom_ifattach calls malloc() with M_WAITOK, we cannot
use mutex lock directly here. Protect ifp->if_afdata instead.
Reported by: grehan
-rw-r--r-- | sys/net/if.c | 23 | ||||
-rw-r--r-- | sys/net/if_var.h | 9 |
2 files changed, 30 insertions, 2 deletions
diff --git a/sys/net/if.c b/sys/net/if.c index d59cde8..0d1738f 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -369,6 +369,8 @@ if_attach(struct ifnet *ifp) struct sockaddr_dl *sdl; struct ifaddr *ifa; + IF_AFDATA_LOCK_INIT(ifp); + ifp->if_afdata_initialized = 0; IFNET_WLOCK(); TAILQ_INSERT_TAIL(&ifnet, ifp, if_link); IFNET_WUNLOCK(); @@ -456,10 +458,8 @@ if_attachdomain(void *dummy) int s; s = splnet(); - IFNET_RLOCK(); for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) if_attachdomain1(ifp); - IFNET_RUNLOCK(); splx(s); } SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST, @@ -473,6 +473,22 @@ if_attachdomain1(struct ifnet *ifp) s = splnet(); + /* + * Since dp->dom_ifattach calls malloc() with M_WAITOK, we + * cannot lock ifp->if_afdata initialization, entirely. + */ + if (IF_AFDATA_TRYLOCK(ifp) == 0) { + splx(s); + return; + } + if (ifp->if_afdata_initialized) { + IF_AFDATA_UNLOCK(ifp); + splx(s); + return; + } + ifp->if_afdata_initialized = 1; + IF_AFDATA_UNLOCK(ifp); + /* address family dependent data region */ bzero(ifp->if_afdata, sizeof(ifp->if_afdata)); for (dp = domains; dp; dp = dp->dom_next) { @@ -576,11 +592,13 @@ if_detach(struct ifnet *ifp) /* Announce that the interface is gone. */ rt_ifannouncemsg(ifp, IFAN_DEPARTURE); + IF_AFDATA_LOCK(ifp); for (dp = domains; dp; dp = dp->dom_next) { if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family]) (*dp->dom_ifdetach)(ifp, ifp->if_afdata[dp->dom_family]); } + IF_AFDATA_UNLOCK(ifp); #ifdef MAC mac_destroy_ifnet(ifp); @@ -590,6 +608,7 @@ if_detach(struct ifnet *ifp) TAILQ_REMOVE(&ifnet, ifp, if_link); IFNET_WUNLOCK(); mtx_destroy(&ifp->if_snd.ifq_mtx); + IF_AFDATA_DESTROY(ifp); splx(s); } diff --git a/sys/net/if_var.h b/sys/net/if_var.h index a1dc0b6..b97a48d 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -180,6 +180,8 @@ struct ifnet { struct label if_label; /* interface MAC label */ void *if_afdata[AF_MAX]; + int if_afdata_initialized; + struct mtx if_afdata_mtx; }; typedef void if_init_f_t(void *); @@ -289,6 +291,13 @@ typedef void if_init_f_t(void *); } while (0) #ifdef _KERNEL +#define IF_AFDATA_LOCK_INIT(ifp) \ + mtx_init(&(ifp)->if_afdata_mtx, "if_afdata", NULL, MTX_DEF) +#define IF_AFDATA_LOCK(ifp) mtx_lock(&(ifp)->if_afdata_mtx) +#define IF_AFDATA_TRYLOCK(ifp) mtx_trylock(&(ifp)->if_afdata_mtx) +#define IF_AFDATA_UNLOCK(ifp) mtx_unlock(&(ifp)->if_afdata_mtx) +#define IF_AFDATA_DESTROY(ifp) mtx_destroy(&(ifp)->if_afdata_mtx) + #define IF_HANDOFF(ifq, m, ifp) if_handoff(ifq, m, ifp, 0) #define IF_HANDOFF_ADJ(ifq, m, ifp, adj) if_handoff(ifq, m, ifp, adj) |