diff --git a/sys/netinet/in_mcast.c b/sys/netinet/in_mcast.c index c3ae14c6a609..afca84e68039 100644 --- a/sys/netinet/in_mcast.c +++ b/sys/netinet/in_mcast.c @@ -1639,16 +1639,29 @@ inp_findmoptions(struct inpcb *inp) * SMPng: NOTE: assumes INP write lock is held. */ void -inp_freemoptions(struct ip_moptions *imo) +inp_freemoptions(struct ip_moptions *imo, struct inpcbinfo *pcbinfo) { + int wlock; if (imo == NULL) return; + + INP_INFO_LOCK_ASSERT(pcbinfo); + wlock = INP_INFO_WLOCKED(pcbinfo); + if (wlock) + INP_INFO_WUNLOCK(pcbinfo); + else + INP_INFO_RUNLOCK(pcbinfo); + KASSERT(imo != NULL, ("%s: ip_moptions is NULL", __func__)); IN_MULTI_LIST_LOCK(); STAILQ_INSERT_TAIL(&imo_gc_list, imo, imo_link); IN_MULTI_LIST_UNLOCK(); taskqueue_enqueue(taskqueue_thread, &imo_gc_task); + if (wlock) + INP_INFO_WLOCK(pcbinfo); + else + INP_INFO_RLOCK(pcbinfo); } static void diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 553491cc10a7..215dd51e70ff 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1388,14 +1388,12 @@ in_pcbfree(struct inpcb *inp) if (imo == NULL && im6o == NULL) return; #endif - INP_INFO_WUNLOCK(pcbinfo); #ifdef INET6 - ip6_freemoptions(im6o); + ip6_freemoptions(im6o, pcbinfo); #endif #ifdef INET - inp_freemoptions(imo); + inp_freemoptions(imo, pcbinfo); #endif - INP_INFO_WLOCK(pcbinfo); } /* diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index 9e7ee5914da5..17e66e1b3e83 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -175,6 +175,7 @@ struct ip; struct inpcb; struct route; struct sockopt; +struct inpcbinfo; VNET_DECLARE(int, ip_defttl); /* default IP ttl */ VNET_DECLARE(int, ipforwarding); /* ip forwarding */ @@ -201,7 +202,7 @@ extern struct pr_usrreqs rip_usrreqs; #define V_rsvp_on VNET(rsvp_on) #define V_drop_redirect VNET(drop_redirect) -void inp_freemoptions(struct ip_moptions *); +void inp_freemoptions(struct ip_moptions *, struct inpcbinfo *); int inp_getmoptions(struct inpcb *, struct sockopt *); int inp_setmoptions(struct inpcb *, struct sockopt *); diff --git a/sys/netinet6/in6_mcast.c b/sys/netinet6/in6_mcast.c index fe8da6685770..023e3a751327 100644 --- a/sys/netinet6/in6_mcast.c +++ b/sys/netinet6/in6_mcast.c @@ -1585,13 +1585,20 @@ in6p_findmoptions(struct inpcb *inp) * SMPng: NOTE: assumes INP write lock is held. */ void -ip6_freemoptions(struct ip6_moptions *imo) +ip6_freemoptions(struct ip6_moptions *imo, struct inpcbinfo *pcbinfo) { struct in6_mfilter *imf; size_t idx, nmships; + int wlock; if (imo == NULL) return; + INP_INFO_LOCK_ASSERT(pcbinfo); + wlock = INP_INFO_WLOCKED(pcbinfo); + if (wlock) + INP_INFO_WUNLOCK(pcbinfo); + else + INP_INFO_RUNLOCK(pcbinfo); nmships = imo->im6o_num_memberships; for (idx = 0; idx < nmships; ++idx) { @@ -1608,6 +1615,10 @@ ip6_freemoptions(struct ip6_moptions *imo) free(imo->im6o_mfilters, M_IN6MFILTER); free(imo->im6o_membership, M_IP6MOPTS); free(imo, M_IP6MOPTS); + if (wlock) + INP_INFO_WLOCK(pcbinfo); + else + INP_INFO_RLOCK(pcbinfo); } /* diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index 6f1c6dbcdd02..7a98fc7c0c7c 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -807,6 +807,7 @@ in6m_rele_locked(struct in6_multi_head *inmh, struct in6_multi *inm) struct ip6_moptions; struct sockopt; +struct inpcbinfo; /* Multicast KPIs. */ int im6o_mc_filter(const struct ip6_moptions *, const struct ifnet *, @@ -823,7 +824,7 @@ void in6m_print(const struct in6_multi *); int in6m_record_source(struct in6_multi *, const struct in6_addr *); void in6m_release_deferred(struct in6_multi *); void in6m_release_list_deferred(struct in6_multi_head *); -void ip6_freemoptions(struct ip6_moptions *); +void ip6_freemoptions(struct ip6_moptions *, struct inpcbinfo *); int ip6_getmoptions(struct inpcb *, struct sockopt *); int ip6_setmoptions(struct inpcb *, struct sockopt *);