aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHajimu UMEMOTO <ume@FreeBSD.org>2003-10-24 16:57:59 +0000
committerHajimu UMEMOTO <ume@FreeBSD.org>2003-10-24 16:57:59 +0000
commit234a35c7144b5f01861212083498924da7de0b79 (patch)
tree750fae5cf23a0f412dffeec3d6ebb79f018f0334
parent7298db81fe87c8967ecf5a73631773ca51e55b41 (diff)
downloadsrc-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.c23
-rw-r--r--sys/net/if_var.h9
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)