Re: TCP accept bug in 2.0 and 2.0.34pre10 patch

Jaroslav Kysela (perex@jcu.cz)
Wed, 22 Apr 1998 10:52:20 +0200 (MET DST)


On Wed, 22 Apr 1998, David S. Miller wrote:

> Date: Tue, 21 Apr 1998 16:14:31 +0200 (MET DST)
> From: Jaroslav Kysela <perex@jcu.cz>
>
> I found strange TCP accept bug in 2.0 kernels (include
> 2.0.34pre10). List of waiting TCP connections (socket ->
> receive_queue) can be at some times corrupted due to interrupts.
>
> This bug can produce some "zombie" sockets which aren't
> passed over accept() to user space, but leaves in kernel forever or
> until some timeout isn't expired.
>
> Are you sure? Please show me the code path which leads to the
> corruption of the receive_queue for a listening socket.

I'm 100% sure, that receive_queue doesn't accept in some cases incoming
connection(s). I added some debugging printk code to tcp_find_establish
function and I found that in some cases is receive_queue empty, but some
established sockets for listen address and port are in kernel (netstat
shows these sockets as established!).

OK. I uploaded source files which generates this bug to:
ftp://ftp.jcu.cz/pub/perex/accept-test.tgz
In this package are three programs:
stest - server test
atest - client test
wwwtest - test for proxy cache (in my case squid), can't be used

You should modify only config.h header file in which is server's hostname
and TCP port which is used for testing. Run 'stest' on server and command
'while [ 1 -eq 1 ]; do ./atest; done' on client side. After some loops
client side hangs and server writes something like 'Accept failed - Try
again'. If you remove timeout for select in stest.c - you can see over
netstat that socket is established in kernel...

I'm using this hardware:

Server - Dual Pentium Pro 200Mhz / 256MB RAM
BusMaster 100Mbit/s Voice Grade adapter from HP (J2585B)
Client - Dual Pentium Pro 150Mhz / 64M RAM
BusMaster 100Mbit/s Voice Grade adapter from HP (J2585B)
Both machines are running SMP 2.0.34pre10 kernel. I'm thinking that bug
should be produced with other hardware, too.

> 1) All interrupt paths in the networking check for the socket
> being locked (via sk->users count, see tcp_rcv() for example)
>
> 2) Only other places sk->receive_queue is touched from a TCP input
> routine is during release_sock() backlog emptying, this happens
> without the socket lock but in start_bh_atomic() sequence so
> no other packet input processing can occur and touch the
> receive_queue
>
> 3) All non-interrupt code which touches receive_queue of a sock,
> does so with the socket locked (look in the tcp_accept() code
> you changed, at all critical moments, lock_sock(sk) has been
> done).

Looks good.

> I'm going to be real difficult about this, because I spent numerous
> non-stop weeks looking for any and all conditions which could lead to
> this, and even after seeing your patch, I still don't know where it
> could possibly occur in the 2.0.x kernel. Please teach me how it can
> happen ;-)

I'm not sure if my patch is best, I'm not expert on linux networking code,
but seems that fixes noticed bug. I run my test (and test for squid)
with patched kernel about 5 hours and bug doesn't occured again. Let me
know about your tests.

> If you figure it out, it might even lead to a fix for the nasty
> "tcp_recvmsg() OOPS" many squid users see, or even this fix you have
> here could be what kills that bug ;-)
>
> Later,
> David S. Miller
> davem@dm.cobaltmicro.com

Jaroslav

-----
Jaroslav Kysela <perex@jcu.cz>
Academic Computer Centre, University of South Bohemia
Branisovska 31, C. Budejovice, CZ-370 05 Czech Republic

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu