svn commit: r333277 - in head/sys: netinet netinet6
Matt Macy
mmacy at FreeBSD.org
Sat May 5 22:40:41 UTC 2018
Author: mmacy
Date: Sat May 5 22:40:40 2018
New Revision: 333277
URL: https://svnweb.freebsd.org/changeset/base/333277
Log:
Currently in_pcbfree will unconditionally wunlock the pcbinfo lock
to avoid a LOR on the multicast list lock in the freemoptions routines.
As it turns out, tcp_usr_detach can acquire the tcbinfo lock readonly.
Trying to wunlock the pcbinfo lock in that context has caused a number
of reported crashes.
This change unclutters in_pcbfree and moves the handling of wunlock vs
runlock of pcbinfo to the freemoptions routine.
Reported by: mjg@, bde@, o.hartmann at walstatt.org
Approved by: sbruno
Modified:
head/sys/netinet/in_mcast.c
head/sys/netinet/in_pcb.c
head/sys/netinet/ip_var.h
head/sys/netinet6/in6_mcast.c
head/sys/netinet6/in6_var.h
Modified: head/sys/netinet/in_mcast.c
==============================================================================
--- head/sys/netinet/in_mcast.c Sat May 5 20:16:08 2018 (r333276)
+++ head/sys/netinet/in_mcast.c Sat May 5 22:40:40 2018 (r333277)
@@ -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
Modified: head/sys/netinet/in_pcb.c
==============================================================================
--- head/sys/netinet/in_pcb.c Sat May 5 20:16:08 2018 (r333276)
+++ head/sys/netinet/in_pcb.c Sat May 5 22:40:40 2018 (r333277)
@@ -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);
}
/*
Modified: head/sys/netinet/ip_var.h
==============================================================================
--- head/sys/netinet/ip_var.h Sat May 5 20:16:08 2018 (r333276)
+++ head/sys/netinet/ip_var.h Sat May 5 22:40:40 2018 (r333277)
@@ -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 *);
Modified: head/sys/netinet6/in6_mcast.c
==============================================================================
--- head/sys/netinet6/in6_mcast.c Sat May 5 20:16:08 2018 (r333276)
+++ head/sys/netinet6/in6_mcast.c Sat May 5 22:40:40 2018 (r333277)
@@ -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);
}
/*
Modified: head/sys/netinet6/in6_var.h
==============================================================================
--- head/sys/netinet6/in6_var.h Sat May 5 20:16:08 2018 (r333276)
+++ head/sys/netinet6/in6_var.h Sat May 5 22:40:40 2018 (r333277)
@@ -807,6 +807,7 @@ in6m_rele_locked(struct in6_multi_head *inmh, struct i
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 *);
More information about the svn-src-head
mailing list