summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2003-10-24 16:57:59 +0000
committerume <ume@FreeBSD.org>2003-10-24 16:57:59 +0000
commiteae980f878292d49d725e3ef2b1b3b15c2914013 (patch)
tree750fae5cf23a0f412dffeec3d6ebb79f018f0334
parentb220e7e690bce5c495774572990e4de021ab2598 (diff)
downloadFreeBSD-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.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 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)
OpenPOWER on IntegriCloud