svn commit: r333905 - in head/sys: netinet netinet6

Matt Macy mmacy at FreeBSD.org
Sun May 20 00:22:30 UTC 2018


Author: mmacy
Date: Sun May 20 00:22:28 2018
New Revision: 333905
URL: https://svnweb.freebsd.org/changeset/base/333905

Log:
  ip(6)_freemoptions: defer imo destruction to epoch callback task
  
  Avoid the ugly unlock / lock of the inpcbinfo where we need to
  figure out what kind of lock we hold by simply deferring the
  operation to another context. (Also a small dependency for
  converting the pcbinfo read lock to epoch)

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
  head/sys/netinet6/ip6_var.h

Modified: head/sys/netinet/in_mcast.c
==============================================================================
--- head/sys/netinet/in_mcast.c	Sat May 19 23:50:54 2018	(r333904)
+++ head/sys/netinet/in_mcast.c	Sun May 20 00:22:28 2018	(r333905)
@@ -165,8 +165,6 @@ static void	inm_reap(struct in_multi *);
 static void inm_release(struct in_multi *);
 static struct ip_moptions *
 		inp_findmoptions(struct inpcb *);
-static void	inp_freemoptions_internal(struct ip_moptions *);
-static void	inp_gcmoptions(void *, int);
 static int	inp_get_source_filters(struct inpcb *, struct sockopt *);
 static int	inp_join_group(struct inpcb *, struct sockopt *);
 static int	inp_leave_group(struct inpcb *, struct sockopt *);
@@ -199,10 +197,6 @@ static SYSCTL_NODE(_net_inet_ip_mcast, OID_AUTO, filte
     CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_ip_mcast_filters,
     "Per-interface stack-wide source filters");
 
-static STAILQ_HEAD(, ip_moptions) imo_gc_list =
-    STAILQ_HEAD_INITIALIZER(imo_gc_list);
-static struct task imo_gc_task = TASK_INITIALIZER(0, inp_gcmoptions, NULL);
-
 #ifdef KTR
 /*
  * Inline function which wraps assertions for a valid ifp.
@@ -1665,46 +1659,15 @@ inp_findmoptions(struct inpcb *inp)
 	return (imo);
 }
 
-/*
- * Discard the IP multicast options (and source filters).  To minimize
- * the amount of work done while holding locks such as the INP's
- * pcbinfo lock (which is used in the receive path), the free
- * operation is performed asynchronously in a separate task.
- *
- * SMPng: NOTE: assumes INP write lock is held.
- */
-void
-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
-inp_freemoptions_internal(struct ip_moptions *imo)
+inp_gcmoptions(epoch_context_t ctx)
 {
+	struct ip_moptions *imo;
 	struct in_mfilter	*imf;
 	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;
@@ -1721,20 +1684,18 @@ inp_freemoptions_internal(struct ip_moptions *imo)
 	free(imo, M_IPMOPTS);
 }
 
-static void
-inp_gcmoptions(void *context, int pending)
+/*
+ * Discard the IP multicast options (and source filters).  To minimize
+ * the amount of work done while holding locks such as the INP's
+ * pcbinfo lock (which is used in the receive path), the free
+ * operation is deferred to the epoch callback task.
+ */
+void
+inp_freemoptions(struct ip_moptions *imo)
 {
-	struct ip_moptions *imo;
-
-	IN_MULTI_LIST_LOCK();
-	while (!STAILQ_EMPTY(&imo_gc_list)) {
-		imo = STAILQ_FIRST(&imo_gc_list);
-		STAILQ_REMOVE_HEAD(&imo_gc_list, imo_link);
-		IN_MULTI_LIST_UNLOCK();
-		inp_freemoptions_internal(imo);
-		IN_MULTI_LIST_LOCK();
-	}
-	IN_MULTI_LIST_UNLOCK();
+	if (imo == NULL)
+		return;
+	epoch_call(net_epoch_preempt, &imo->imo_epoch_ctx, inp_gcmoptions);
 }
 
 /*

Modified: head/sys/netinet/in_pcb.c
==============================================================================
--- head/sys/netinet/in_pcb.c	Sat May 19 23:50:54 2018	(r333904)
+++ head/sys/netinet/in_pcb.c	Sun May 20 00:22:28 2018	(r333905)
@@ -1382,18 +1382,14 @@ in_pcbfree(struct inpcb *inp)
 #ifdef MAC
 	mac_inpcb_destroy(inp);
 #endif
-	if (!in_pcbrele_wlocked(inp))
-		INP_WUNLOCK(inp);
-#if defined(INET) && defined(INET6)
-	if (imo == NULL && im6o == NULL)
-		return;
-#endif
 #ifdef INET6
-	ip6_freemoptions(im6o, pcbinfo);
+	ip6_freemoptions(im6o);
 #endif
 #ifdef INET
-	inp_freemoptions(imo, pcbinfo);
+	inp_freemoptions(imo);
 #endif
+	if (!in_pcbrele_wlocked(inp))
+		INP_WUNLOCK(inp);
 }
 
 /*
@@ -1545,6 +1541,8 @@ in_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet
 			/*
 			 * Drop multicast group membership if we joined
 			 * through the interface being detached.
+			 *
+			 * XXX This can all be deferred to an epoch_call
 			 */
 			for (i = 0, gap = 0; i < imo->imo_num_memberships;
 			    i++) {

Modified: head/sys/netinet/ip_var.h
==============================================================================
--- head/sys/netinet/ip_var.h	Sat May 19 23:50:54 2018	(r333904)
+++ head/sys/netinet/ip_var.h	Sun May 20 00:22:28 2018	(r333905)
@@ -36,6 +36,7 @@
 #define	_NETINET_IP_VAR_H_
 
 #include <sys/queue.h>
+#include <sys/epoch.h>
 
 /*
  * Overlay for ip header used by other protocols (tcp, udp).
@@ -95,7 +96,7 @@ struct ip_moptions {
 	u_short	imo_max_memberships;	/* max memberships this socket */
 	struct	in_multi **imo_membership;	/* group memberships */
 	struct	in_mfilter *imo_mfilters;	/* source filters */
-	STAILQ_ENTRY(ip_moptions) imo_link;
+	struct	epoch_context imo_epoch_ctx;
 };
 
 struct	ipstat {
@@ -202,7 +203,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 *, struct inpcbinfo *);
+void	inp_freemoptions(struct ip_moptions *);
 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 19 23:50:54 2018	(r333904)
+++ head/sys/netinet6/in6_mcast.c	Sun May 20 00:22:28 2018	(r333905)
@@ -1616,22 +1616,19 @@ in6p_findmoptions(struct inpcb *inp)
  * Discard the IPv6 multicast options (and source filters).
  *
  * SMPng: NOTE: assumes INP write lock is held.
+ *
+ * XXX can all be safely deferred to epoch_call
+ *
  */
-void
-ip6_freemoptions(struct ip6_moptions *imo, struct inpcbinfo *pcbinfo)
+
+static void
+inp_gcmoptions(epoch_context_t ctx)
 {
+	struct ip6_moptions *imo;
 	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);
+	imo =  __containerof(ctx, struct ip6_moptions, imo6_epoch_ctx);
 
 	nmships = imo->im6o_num_memberships;
 	for (idx = 0; idx < nmships; ++idx) {
@@ -1648,10 +1645,14 @@ ip6_freemoptions(struct ip6_moptions *imo, struct inpc
 		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);
+}
+
+void
+ip6_freemoptions(struct ip6_moptions *imo)
+{
+	if (imo == NULL)
+		return;
+	epoch_call(net_epoch_preempt, &imo->imo6_epoch_ctx, inp_gcmoptions);
 }
 
 /*

Modified: head/sys/netinet6/in6_var.h
==============================================================================
--- head/sys/netinet6/in6_var.h	Sat May 19 23:50:54 2018	(r333904)
+++ head/sys/netinet6/in6_var.h	Sun May 20 00:22:28 2018	(r333905)
@@ -810,7 +810,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 *, struct inpcbinfo *);
+void	ip6_freemoptions(struct ip6_moptions *);
 int	ip6_getmoptions(struct inpcb *, struct sockopt *);
 int	ip6_setmoptions(struct inpcb *, struct sockopt *);
 

Modified: head/sys/netinet6/ip6_var.h
==============================================================================
--- head/sys/netinet6/ip6_var.h	Sat May 19 23:50:54 2018	(r333904)
+++ head/sys/netinet6/ip6_var.h	Sun May 20 00:22:28 2018	(r333905)
@@ -66,6 +66,8 @@
 #ifndef _NETINET6_IP6_VAR_H_
 #define _NETINET6_IP6_VAR_H_
 
+#include <sys/epoch.h>
+
 /*
  * IP6 reassembly queue structure.  Each fragment
  * being reassembled is attached to one of these structures.
@@ -121,6 +123,7 @@ struct ip6_moptions {
 	u_short	im6o_max_memberships;	/* max memberships this socket */
 	struct	in6_multi **im6o_membership;	/* group memberships */
 	struct	in6_mfilter *im6o_mfilters;	/* source filters */
+	struct	epoch_context imo6_epoch_ctx;
 };
 
 /*


More information about the svn-src-head mailing list