From 7442cbe0e22d6d66beb54b1931a480be48cf1455 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Mon, 8 Sep 2014 19:46:28 +0800 Subject: [PATCH] tcp: Dispatch tcp_drain to netisrs to run - Avoid two extra M_WAITOK mallocs - Simplify drain logic, since inpcb marker is no longer needed --- sys/netinet/tcp_subr.c | 83 +++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index fde6067f59..fe1d0e5fa7 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -281,6 +281,9 @@ static void tcp_notify (struct inpcb *, int); struct tcp_stats tcpstats_percpu[MAXCPU] __cachealign; +static struct netmsg_base tcp_drain_netmsg[MAXCPU]; +static void tcp_drain_dispatch(netmsg_t nmsg); + static int sysctl_tcpstats(SYSCTL_HANDLER_ARGS) { @@ -410,6 +413,14 @@ tcp_init(void) for (cpu = 0; cpu < ncpus2; ++cpu) bzero(&tcpstats_percpu[cpu], sizeof(struct tcp_stats)); + /* + * Initialize netmsgs for TCP drain + */ + for (cpu = 0; cpu < ncpus2; ++cpu) { + netmsg_init(&tcp_drain_netmsg[cpu], NULL, &netisr_adone_rport, + MSGF_PRIORITY, tcp_drain_dispatch); + } + syncache_init(); netisr_register_rollup(tcp_willblock, NETISR_ROLLUP_PRIO_TCP); } @@ -1053,23 +1064,22 @@ no_valid_rt: } static __inline void -tcp_drain_oncpu(struct inpcbhead *head) +tcp_drain_oncpu(struct inpcbinfo *pcbinfo) { - struct inpcb *marker; + struct inpcbhead *head = &pcbinfo->pcblisthead; struct inpcb *inpb; - struct tcpcb *tcpb; - struct tseg_qent *te; /* - * Allows us to block while running the list + * Since we run in netisr, it is MP safe, even if + * we block during the inpcb list iteration, i.e. + * we don't need to use inpcb marker here. */ - marker = kmalloc(sizeof(struct inpcb), M_TEMP, M_WAITOK|M_ZERO); - marker->inp_flags |= INP_PLACEMARKER; - LIST_INSERT_HEAD(head, marker, inp_list); + KASSERT(&curthread->td_msgport == netisr_cpuport(pcbinfo->cpu), + ("not in correct netisr")); - while ((inpb = LIST_NEXT(marker, inp_list)) != NULL) { - LIST_REMOVE(marker, inp_list); - LIST_INSERT_AFTER(inpb, marker, inp_list); + LIST_FOREACH(inpb, head, inp_list) { + struct tcpcb *tcpb; + struct tseg_qent *te; if ((inpb->inp_flags & INP_PLACEMARKER) == 0 && (tcpb = intotcpcb(inpb)) != NULL && @@ -1083,28 +1093,34 @@ tcp_drain_oncpu(struct inpcbhead *head) /* retry */ } } - LIST_REMOVE(marker, inp_list); - kfree(marker, M_TEMP); } -struct netmsg_tcp_drain { - struct netmsg_base base; - struct inpcbhead *nm_head; -}; +static void +tcp_drain_dispatch(netmsg_t nmsg) +{ + crit_enter(); + lwkt_replymsg(&nmsg->lmsg, 0); /* reply ASAP */ + crit_exit(); + + tcp_drain_oncpu(&tcbinfo[mycpuid]); +} static void -tcp_drain_handler(netmsg_t msg) +tcp_drain_ipi(void *arg __unused) { - struct netmsg_tcp_drain *nm = (void *)msg; + int cpu = mycpuid; + struct lwkt_msg *msg = &tcp_drain_netmsg[cpu].lmsg; - tcp_drain_oncpu(nm->nm_head); - lwkt_replymsg(&nm->base.lmsg, 0); + crit_enter(); + if (msg->ms_flags & MSGF_DONE) + lwkt_sendmsg_oncpu(netisr_cpuport(cpu), msg); + crit_exit(); } void tcp_drain(void) { - int cpu; + cpumask_t mask; if (!do_tcpdrain) return; @@ -1116,23 +1132,14 @@ tcp_drain(void) * reassembly queue should be flushed, but in a situation * where we're really low on mbufs, this is potentially * useful. + * YYY: We may consider run tcp_drain_oncpu directly here, + * however, that will require M_WAITOK memory allocation + * for the inpcb marker. */ - for (cpu = 0; cpu < ncpus2; cpu++) { - struct netmsg_tcp_drain *nm; - - if (cpu == mycpu->gd_cpuid) { - tcp_drain_oncpu(&tcbinfo[cpu].pcblisthead); - } else { - nm = kmalloc(sizeof(struct netmsg_tcp_drain), - M_LWKTMSG, M_NOWAIT); - if (nm == NULL) - continue; - netmsg_init(&nm->base, NULL, &netisr_afree_rport, - 0, tcp_drain_handler); - nm->nm_head = &tcbinfo[cpu].pcblisthead; - lwkt_sendmsg(netisr_cpuport(cpu), &nm->base.lmsg); - } - } + CPUMASK_ASSBMASK(mask, ncpus2); + CPUMASK_ANDMASK(mask, smp_active_mask); + if (CPUMASK_TESTNZERO(mask)) + lwkt_send_ipiq_mask(mask, tcp_drain_ipi, NULL); } /* -- 2.41.0