TCP accept bug in 2.0 and 2.0.34pre10 patch

Jaroslav Kysela (perex@jcu.cz)
Tue, 21 Apr 1998 16:14:31 +0200 (MET DST)


Hi!

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.
I found this bug on 100Mbit/s Voice Grade network when I tested
performance of squid cache program with my tests (test program allows open
up to 2500 simultaneous connections to cache). Server and client are SMP
machines (Pentium Pro) with 2.0.33 + 2.0.34pre10 kernel. I wrote two
(server & client) programs which simulate above situation (these programs
are available at request) and bellow patch for kernel is result of my
work. With this patch wasn't bug produced again... Maybe Alan Cox should
verify this patch and include it to 2.0.34 kernel. Thank you...
I have a bug report for 2.0.34pre10, too. When I build modularized
kernel with 2.0.33+34pre10 patch then network isn't working properly. I can
insert module with network driver, but I can't initialize it. Program
ifconfig shows that eth0 is something like AMPR NET/ROM - good string is
10Mbs Ethernet - and SIOC* commands isn't working thus network can't be
initialized. Kernel 2.0.33 without any patches is working properly.
Configuration is nearly same for both kernels (2.0.33pre10 have more
drivers available). Any ideas? Looks that some device initialization
structures are corrupted...

Jaroslav

============================
--- linux/net/ipv4/tcp.c.old Tue Apr 21 11:43:46 1998
+++ linux/net/ipv4/tcp.c Tue Apr 21 11:45:16 1998
@@ -1548,8 +1548,13 @@

static inline void tcp_eat_skb(struct sock *sk, struct sk_buff * skb)
{
+ unsigned long flags;
+
+ save_flags( flags );
+ cli();
skb->sk = sk;
__skb_unlink(skb, &sk->receive_queue);
+ restore_flags( flags );
kfree_skb(skb, FREE_READ);
}

@@ -2088,6 +2093,7 @@

static struct sock *tcp_accept(struct sock *sk, int flags)
{
+ unsigned long iflags;
int error;
struct sk_buff *skb;
struct sock *newsk = NULL;
@@ -2106,8 +2112,11 @@
skb = tcp_find_established(sk);
if (skb) {
got_new_connect:
+ save_flags( iflags );
+ cli();
__skb_unlink(skb, &sk->receive_queue);
newsk = skb->sk;
+ restore_flags( iflags );
kfree_skb(skb, FREE_READ);
sk->ack_backlog--;
error = 0;
--- linux/net/ipv4/tcp_input.c.old Tue Apr 21 11:43:58 1998
+++ linux/net/ipv4/tcp_input.c Tue Apr 21 10:42:23 1998
@@ -1844,6 +1844,7 @@
*/
static inline void tcp_insert_skb(struct sk_buff * skb, struct sk_buff_head * list)
{
+ unsigned long flags;
struct sk_buff * prev, * next;
u32 seq;

@@ -1852,6 +1853,8 @@
* on the assumption that we get the packets in order)
*/
seq = skb->seq;
+ save_flags( flags );
+ cli();
prev = list->prev;
next = (struct sk_buff *) list;
for (;;) {
@@ -1861,6 +1864,7 @@
prev = prev->prev;
}
__skb_insert(skb, prev, next, list);
+ restore_flags( flags );
}

/*
=========================

-----
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