diff options
author | Hajimu UMEMOTO <ume@FreeBSD.org> | 2003-10-24 16:57:59 +0000 |
---|---|---|
committer | Hajimu UMEMOTO <ume@FreeBSD.org> | 2003-10-24 16:57:59 +0000 |
commit | 234a35c7144b5f01861212083498924da7de0b79 (patch) | |
tree | 750fae5cf23a0f412dffeec3d6ebb79f018f0334 | |
parent | 7298db81fe87c8967ecf5a73631773ca51e55b41 (diff) | |
download | src-234a35c7144b5f01861212083498924da7de0b79.tar.gz src-234a35c7144b5f01861212083498924da7de0b79.zip |
Since dp->dom_ifattach calls malloc() with M_WAITOK, we cannot
use mutex lock directly here. Protect ifp->if_afdata instead.
Reported by: grehan
Notes
Notes:
svn path=/head/; revision=121470
-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 d59cde8ffaee..0d1738f3b1cd 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 a1dc0b6a0e89..b97a48dbff79 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) |