Date: Sun, 20 May 2018 00:22:28 +0000 (UTC) From: Matt Macy <mmacy@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r333905 - in head/sys: netinet netinet6 Message-ID: <201805200022.w4K0MSAl046636@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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; }; /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201805200022.w4K0MSAl046636>