diff options
author | bms <bms@FreeBSD.org> | 2004-07-04 18:32:54 +0000 |
---|---|---|
committer | bms <bms@FreeBSD.org> | 2004-07-04 18:32:54 +0000 |
commit | f58c85659673b7c072819abbd7c5a27785b5c2fb (patch) | |
tree | e8809577df2cf1ec4c8a69af3bbffc5f613c62fc /sys/net/if_vlan.c | |
parent | 423979003aba4f7f09234e090a743183e3957b0f (diff) | |
download | FreeBSD-src-f58c85659673b7c072819abbd7c5a27785b5c2fb.zip FreeBSD-src-f58c85659673b7c072819abbd7c5a27785b5c2fb.tar.gz |
Workaround a locking problem in vlan(4). vlan_setmulti() may be called
with sleepable locks held from further up in the network stack, and
attempts to allocate memory to hold multicast group membership information
with M_WAITOK.
This panic was triggered specifically when an exiting routing daemon
process closes its raw sockets after joining multicast groups on them.
While we're here, comment some possible locking badness.
PR: kern/48560
Diffstat (limited to 'sys/net/if_vlan.c')
-rw-r--r-- | sys/net/if_vlan.c | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c index a981dd5..da9b280 100644 --- a/sys/net/if_vlan.c +++ b/sys/net/if_vlan.c @@ -144,6 +144,9 @@ struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL, IF_MAXUNIT, * traffic that it doesn't really want, which ends up being discarded * later by the upper protocol layers. Unfortunately, there's no way * to avoid this: there really is only one physical interface. + * + * XXX: There is a possible race here if more than one thread is + * modifying the multicast state of the vlan interface at the same time. */ static int vlan_setmulti(struct ifnet *ifp) @@ -155,6 +158,8 @@ vlan_setmulti(struct ifnet *ifp) struct sockaddr_dl sdl; int error; + /*VLAN_LOCK_ASSERT();*/ + /* Find the parent. */ sc = ifp->if_softc; ifp_p = sc->ifv_p; @@ -188,7 +193,9 @@ vlan_setmulti(struct ifnet *ifp) TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; - mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_WAITOK); + mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_NOWAIT); + if (mc == NULL) + return (ENOMEM); bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), (char *)&mc->mc_addr, ETHER_ADDR_LEN); SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries); @@ -716,7 +723,7 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p) * Configure multicast addresses that may already be * joined on the vlan device. */ - (void)vlan_setmulti(&ifv->ifv_if); + (void)vlan_setmulti(&ifv->ifv_if); /* XXX: VLAN lock held */ return (0); } @@ -981,7 +988,9 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCADDMULTI: case SIOCDELMULTI: + /*VLAN_LOCK();*/ error = vlan_setmulti(ifp); + /*VLAN_UNLOCK();*/ break; default: error = EINVAL; |