Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F115588806
D36887.id111475.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D36887.id111475.diff
View Options
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -2864,12 +2864,12 @@
}
while ((inp = inp_next(&inpi)) != NULL)
if (inp->inp_gencnt == params->sop_id) {
- if (inp->inp_flags & INP_DROPPED) {
+ if ((inp->inp_flags & INP_DROPPED) ||
+ inp->inp_socket == NULL) {
INP_WUNLOCK(inp);
return (ECONNRESET);
}
so = inp->inp_socket;
- KASSERT(so != NULL, ("inp_socket == NULL"));
soref(so);
error = (*ctloutput_set)(inp, &sopt);
sorele(so);
diff --git a/sys/netinet/siftr.c b/sys/netinet/siftr.c
--- a/sys/netinet/siftr.c
+++ b/sys/netinet/siftr.c
@@ -896,9 +896,10 @@
/*
* If we can't find the TCP control block (happens occasionaly for a
- * packet sent during the shutdown phase of a TCP connection), bail
+ * packet sent during the shutdown phase of a TCP connection),
+ * or we're in the timewait state, bail
*/
- if (tp == NULL) {
+ if (tp == NULL || tp->t_state == TCPS_TIME_WAIT) {
if (dir == PFIL_IN)
ss->nskip_in_tcpcb++;
else
@@ -1080,9 +1081,10 @@
/*
* If we can't find the TCP control block (happens occasionaly for a
- * packet sent during the shutdown phase of a TCP connection), bail
+ * packet sent during the shutdown phase of a TCP connection),
+ * or we're in the timewait state, bail.
*/
- if (tp == NULL) {
+ if (tp == NULL || tp->t_state == TCPS_TIME_WAIT) {
if (dir == PFIL_IN)
ss->nskip_in_tcpcb++;
else
diff --git a/sys/netinet/tcp_lro.c b/sys/netinet/tcp_lro.c
--- a/sys/netinet/tcp_lro.c
+++ b/sys/netinet/tcp_lro.c
@@ -1359,7 +1359,8 @@
tp = intotcpcb(inp);
/* Check if the inp is dead, Jim. */
- if (tp == NULL || (inp->inp_flags & INP_DROPPED)) {
+ if (tp == NULL || (inp->inp_flags & INP_DROPPED) ||
+ tp->t_state == TCPS_TIME_WAIT) {
INP_WUNLOCK(inp);
return (TCP_LRO_CANNOT);
}
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -2563,18 +2563,29 @@
#endif
in_pcbdrop(inp);
TCPSTAT_INC(tcps_closed);
- if (tp->t_state != TCPS_CLOSED)
+ /*
+ * Connections in TIME_WAIT may have the socket already detached,
+ * but tcp_use_detach() didn't free pcb. In this case it our job
+ * to free it.
+ */
+ if ((so = inp->inp_socket) != NULL) {
+ if (tp->t_state != TCPS_CLOSED)
+ tcp_state_change(tp, TCPS_CLOSED);
+ soisdisconnected(so);
+ if (inp->inp_flags & INP_SOCKREF) {
+ inp->inp_flags &= ~INP_SOCKREF;
+ INP_WUNLOCK(inp);
+ sorele(so);
+ return (NULL);
+ } else
+ return (tp); /* locked */
+ } else {
+ MPASS(tp->t_state == TCPS_TIME_WAIT);
tcp_state_change(tp, TCPS_CLOSED);
- KASSERT(inp->inp_socket != NULL, ("tcp_close: inp_socket NULL"));
- so = inp->inp_socket;
- soisdisconnected(so);
- if (inp->inp_flags & INP_SOCKREF) {
- inp->inp_flags &= ~INP_SOCKREF;
- INP_WUNLOCK(inp);
- sorele(so);
+ tcp_discardcb(tp);
+ in_pcbfree(inp);
return (NULL);
}
- return (tp);
}
/*
@@ -3693,10 +3704,12 @@
#endif
}
if (inp != NULL) {
- if ((inp->inp_flags & INP_DROPPED) == 0 &&
- !SOLISTENING(inp->inp_socket)) {
- tp = intotcpcb(inp);
- tp = tcp_drop(tp, ECONNABORTED);
+ tp = intotcpcb(inp);
+ if ((inp->inp_flags & INP_DROPPED) == 0) {
+ if (tp->t_state == TCPS_TIME_WAIT)
+ tp = tcp_close(tp);
+ else if (!SOLISTENING(inp->inp_socket))
+ tp = tcp_drop(tp, ECONNABORTED);
if (tp != NULL)
INP_WUNLOCK(inp);
} else
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -116,6 +116,7 @@
tcp_twstart(struct tcpcb *tp)
{
struct inpcb *inp = tp->t_inpcb;
+ struct socket *so = inp->inp_socket;
#ifdef INET6
bool isipv6 = inp->inp_inc.inc_flags & INC_ISIPV6;
#endif
@@ -128,7 +129,7 @@
"(inp->inp_flags & INP_DROPPED) != 0"));
tcp_state_change(tp, TCPS_TIME_WAIT);
- soisdisconnected(inp->inp_socket);
+ soisdisconnected(so);
if (tp->t_flags & TF_ACKNOW)
tcp_output(tp);
@@ -149,7 +150,23 @@
}
tcp_timer_activate(tp, TT_2MSL, 2 * V_tcp_msl);
- INP_WUNLOCK(inp);
+
+ /*
+ * INP_SOCKREF means that the socket had been close(2)d by the
+ * userland and it is the inpcb that keeps socket in memory.
+ * To preserve memory, we want to release the socket now, not
+ * when the TIME_WAIT state expires. Note that tcp_usr_detach()
+ * has a special case to handle a call from here.
+ */
+ if (inp->inp_flags & INP_SOCKREF) {
+ inp->inp_flags &= ~INP_SOCKREF;
+#ifdef TCPHPTS
+ tcp_hpts_remove(tp->t_inpcb);
+#endif
+ INP_WUNLOCK(inp);
+ sorele(so);
+ } else
+ INP_WUNLOCK(inp);
}
/*
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -216,13 +216,27 @@
tp = intotcpcb(inp);
- KASSERT(inp->inp_flags & INP_DROPPED ||
- tp->t_state < TCPS_SYN_SENT,
- ("%s: inp %p not dropped or embryonic", __func__, inp));
-
- tcp_discardcb(tp);
- in_pcbdetach(inp);
- in_pcbfree(inp);
+ /*
+ * Note on connections in TIME_WAIT.
+ *
+ * There are two cases here:
+ * - We went through tcp_close() in our call stack, and the connection
+ * shall be processed normally. Such pcbs are always marked with
+ * INP_DROPPED.
+ * - We are detaching pcb from the socket in tcp_twstart(), for memory
+ * saving purposes. The pcb shall remain.
+ */
+ if (inp->inp_flags & INP_DROPPED) {
+ KASSERT(tp->t_state < TCPS_SYN_SENT,
+ ("%s: dropped inp %p not embryonic", __func__, inp));
+ tcp_discardcb(tp);
+ in_pcbdetach(inp);
+ in_pcbfree(inp);
+ } else {
+ MPASS(tp->t_state == TCPS_TIME_WAIT);
+ in_pcbdetach(inp);
+ INP_WUNLOCK(inp);
+ }
}
#ifdef INET
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Apr 26, 6:05 PM (12 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17807531
Default Alt Text
D36887.id111475.diff (5 KB)
Attached To
Mode
D36887: tcp: restore some memory savings associated with TIME_WAIT state
Attached
Detach File
Event Timeline
Log In to Comment