diff options
Diffstat (limited to 'freebsd/sys/netinet/in_mcast.c')
-rw-r--r-- | freebsd/sys/netinet/in_mcast.c | 39 |
1 files changed, 28 insertions, 11 deletions
diff --git a/freebsd/sys/netinet/in_mcast.c b/freebsd/sys/netinet/in_mcast.c index ea4779fc..e0fd4c37 100644 --- a/freebsd/sys/netinet/in_mcast.c +++ b/freebsd/sys/netinet/in_mcast.c @@ -233,8 +233,13 @@ static void inm_init(void) taskqgroup_config_gtask_init(NULL, &free_gtask, inm_release_task, "inm release task"); } +#ifdef EARLY_AP_STARTUP SYSINIT(inm_init, SI_SUB_SMP + 1, SI_ORDER_FIRST, inm_init, NULL); +#else +SYSINIT(inm_init, SI_SUB_ROOT_CONF - 1, SI_ORDER_FIRST, + inm_init, NULL); +#endif void @@ -260,7 +265,10 @@ inm_disconnect(struct in_multi *inm) ifma = inm->inm_ifma; if_ref(ifp); - CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link); + if (ifma->ifma_flags & IFMA_F_ENQUEUED) { + CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link); + ifma->ifma_flags &= ~IFMA_F_ENQUEUED; + } MCDPRINTF("removed ifma: %p from %s\n", ifma, ifp->if_xname); if ((ll_ifma = ifma->ifma_llifma) != NULL) { MPASS(ifma != ll_ifma); @@ -268,7 +276,10 @@ inm_disconnect(struct in_multi *inm) MPASS(ll_ifma->ifma_llifma == NULL); MPASS(ll_ifma->ifma_ifp == ifp); if (--ll_ifma->ifma_refcount == 0) { - CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, ifma_link); + if (ll_ifma->ifma_flags & IFMA_F_ENQUEUED) { + CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, ifma_link); + ll_ifma->ifma_flags &= ~IFMA_F_ENQUEUED; + } MCDPRINTF("removed ll_ifma: %p from %s\n", ll_ifma, ifp->if_xname); if_freemulti(ll_ifma); ifma_restart = true; @@ -1581,23 +1592,24 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) * Begin state merge transaction at IGMP layer. */ IN_MULTI_LOCK(); - IN_MULTI_LIST_LOCK(); CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); + IN_MULTI_LIST_LOCK(); error = inm_merge(inm, imf); if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); + IN_MULTI_LIST_UNLOCK(); goto out_in_multi_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); error = igmp_change_state(inm); + IN_MULTI_LIST_UNLOCK(); if (error) CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); out_in_multi_locked: IN_MULTI_UNLOCK(); - IN_MULTI_UNLOCK(); out_imf_rollback: if (error) imf_rollback(imf); @@ -1664,16 +1676,13 @@ inp_findmoptions(struct inpcb *inp) } static void -inp_gcmoptions(epoch_context_t ctx) +inp_gcmoptions(struct ip_moptions *imo) { - struct ip_moptions *imo; struct in_mfilter *imf; struct in_multi *inm; struct ifnet *ifp; size_t idx, nmships; - imo = __containerof(ctx, struct ip_moptions, imo_epoch_ctx); - nmships = imo->imo_num_memberships; for (idx = 0; idx < nmships; ++idx) { imf = imo->imo_mfilters ? &imo->imo_mfilters[idx] : NULL; @@ -1709,7 +1718,7 @@ inp_freemoptions(struct ip_moptions *imo) { if (imo == NULL) return; - epoch_call(net_epoch_preempt, &imo->imo_epoch_ctx, inp_gcmoptions); + inp_gcmoptions(imo); } /* @@ -2261,7 +2270,8 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) __func__); IN_MULTI_LIST_UNLOCK(); goto out_imo_free; - } + } + inm_acquire(inm); imo->imo_membership[idx] = inm; } else { CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); @@ -2301,6 +2311,12 @@ out_in_multi_locked: out_imo_free: if (error && is_new) { + inm = imo->imo_membership[idx]; + if (inm != NULL) { + IN_MULTI_LIST_LOCK(); + inm_release_deferred(inm); + IN_MULTI_LIST_UNLOCK(); + } imo->imo_membership[idx] = NULL; --imo->imo_num_memberships; } @@ -2494,6 +2510,7 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); + IN_MULTI_LIST_UNLOCK(); goto out_in_multi_locked; } @@ -2738,12 +2755,12 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) INP_WLOCK_ASSERT(inp); IN_MULTI_LOCK(); - IN_MULTI_LIST_LOCK(); /* * Begin state merge transaction at IGMP layer. */ CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); + IN_MULTI_LIST_LOCK(); error = inm_merge(inm, imf); if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); |