Bug 49915

Summary: Excessive Send-Q memory waste
Product: [Retired] Red Hat Linux Reporter: Need Real Name <jplevyak>
Component: kernelAssignee: David Miller <davem>
Status: CLOSED NOTABUG QA Contact: Brock Organ <borgan>
Severity: high Docs Contact:
Priority: medium    
Version: 7.1CC: jplevyak
Target Milestone: ---   
Target Release: ---   
Hardware: All   
OS: Linux   
URL: http://personal.inktomi.com/~jplevyak/lastack.html
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2001-08-02 18:10:54 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Need Real Name 2001-07-25 01:32:22 UTC
From Bugzilla Helper:
User-Agent: Mozilla/4.75 [en] (X11; U; Linux 2.4.7 i686)

Description of problem:
Both 2.2.X kernels and 2.4.X kernels fail to free sk->write_queue memory
on transition from TCP_CLOSE_WAIT to TCP_LAST_ACK.  For certain ill behaved
connections, this results in the socket buffer being full in LAST_ACK for a
long
time.  Many of such connections can cause the kernel to waste hundreds of
MB
(if available).

How reproducible:
Always

Steps to Reproduce:
1. run an HTTP proxy (e.g. traffic_server (Inktomi) or likely squid) 
2. the proxy sends data
3. before the socket buffer drains a FIN arrives from the client
   (connection is now in CLOSE_WAIT with data in Send-Q)
4. the proxy closes the connection (connection now in LAST_ACK) FIN sent
5. ACK not received (lost)
6. memory wasted in Send-Q		
	

Actual Results:  after a long run of clients with the above behavior, 
netstat reports hundreds of megabytes of data in Send-Q of connections
in LAST_ACK state.

Expected Results:  netstat reports all connections in LAST_ACK have at most
the FIN packet waiting

Additional info:

See the URL also for the patches, but here is the one for 2.4.7:

*** linux-2.4.7.orig/net/ipv4/tcp.c     Tue Jul 24 14:48:58 2001
--- linux-2.4.7/net/ipv4/tcp.c  Tue Jul 24 14:51:48 2001
***************
*** 1711,1716 ****
--- 1711,1722 ----
        int next = (int) new_state[sk->state];
        int ns = (next & TCP_STATE_MASK);
  
+       if (sk->state == TCP_CLOSE_WAIT) {
+               struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+               tcp_writequeue_purge(sk);
+               tp->send_head = 0;
+       }
+ 
        tcp_set_state(sk, ns);
  
        return (next & TCP_ACTION_FIN);

Basically just purge the write_queue on this transition.

I have tested this code and it works.

Comment 1 Doug Ledford 2001-08-02 18:10:50 UTC
This is assigned to the wrong person.  Re-assigning.

Comment 2 David Miller 2001-08-03 05:38:56 UTC
This suggested change is invalid.

The sender must attempt to send the rest of the send queue
before the ACK.  So if the socket is holding onto the memory
this is because the receiving side has not ACK'd the data yet.
Once the data is ACK'd the send queue data will be freed up.

shutdown(SEND) or close() does not mean "all pending send data
is invalid", it means "send all pending data then FIN".

We free up the data as early as is legally possible.