summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlstewart <lstewart@FreeBSD.org>2011-11-27 02:32:08 +0000
committerlstewart <lstewart@FreeBSD.org>2011-11-27 02:32:08 +0000
commit6b64070ea6b8262814e61de86b09360723446181 (patch)
treea94981686e2c2695222aea3fa06b68903543ede5
parent519601e53391dc53d1baca7a168a0a07700f925f (diff)
downloadFreeBSD-src-6b64070ea6b8262814e61de86b09360723446181.zip
FreeBSD-src-6b64070ea6b8262814e61de86b09360723446181.tar.gz
Plug a TCP reassembly UMA zone leak introduced in r226113 by only using the
backup stack queue entry when the zone is exhausted, otherwise we leak a zone allocation each time we plug a hole in the reassembly queue. Reported by: many on freebsd-stable@ (thread: "TCP Reassembly Issues") Tested by: many on freebsd-stable@ (thread: "TCP Reassembly Issues") Reviewed by: bz (very brief sanity check) MFC after: 3 days
-rw-r--r--sys/netinet/tcp_reass.c39
1 files changed, 22 insertions, 17 deletions
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index b694f00..e52b97d 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -233,23 +233,28 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m)
* when the zone is exhausted. Otherwise we may get stuck.
*/
te = uma_zalloc(V_tcp_reass_zone, M_NOWAIT);
- if (te == NULL && th->th_seq != tp->rcv_nxt) {
- TCPSTAT_INC(tcps_rcvmemdrop);
- m_freem(m);
- *tlenp = 0;
- if ((s = tcp_log_addrs(&tp->t_inpcb->inp_inc, th, NULL, NULL))) {
- log(LOG_DEBUG, "%s; %s: global zone limit reached, "
- "segment dropped\n", s, __func__);
- free(s, M_TCPLOG);
- }
- return (0);
- } else if (th->th_seq == tp->rcv_nxt) {
- bzero(&tqs, sizeof(struct tseg_qent));
- te = &tqs;
- if ((s = tcp_log_addrs(&tp->t_inpcb->inp_inc, th, NULL, NULL))) {
- log(LOG_DEBUG, "%s; %s: global zone limit reached, "
- "using stack for missing segment\n", s, __func__);
- free(s, M_TCPLOG);
+ if (te == NULL) {
+ if (th->th_seq != tp->rcv_nxt) {
+ TCPSTAT_INC(tcps_rcvmemdrop);
+ m_freem(m);
+ *tlenp = 0;
+ if ((s = tcp_log_addrs(&tp->t_inpcb->inp_inc, th, NULL,
+ NULL))) {
+ log(LOG_DEBUG, "%s; %s: global zone limit "
+ "reached, segment dropped\n", s, __func__);
+ free(s, M_TCPLOG);
+ }
+ return (0);
+ } else {
+ bzero(&tqs, sizeof(struct tseg_qent));
+ te = &tqs;
+ if ((s = tcp_log_addrs(&tp->t_inpcb->inp_inc, th, NULL,
+ NULL))) {
+ log(LOG_DEBUG,
+ "%s; %s: global zone limit reached, using "
+ "stack for missing segment\n", s, __func__);
+ free(s, M_TCPLOG);
+ }
}
}
tp->t_segqlen++;
OpenPOWER on IntegriCloud