netdev
[Top] [All Lists]

Re: [Fwd: Re: possible bug x86 2.4.2 SMP in IP receive stack]

To: andrewm@xxxxxxxxxx (Andrew Morton)
Subject: Re: [Fwd: Re: possible bug x86 2.4.2 SMP in IP receive stack]
From: kuznet@xxxxxxxxxxxxx
Date: Wed, 7 Mar 2001 18:59:38 +0300 (MSK)
Cc: pp@xxxxxxxxxxxxxx, feldy@xxxxxxxx, netdev@xxxxxxxxxxx, davem@xxxxxxxxxx (Dave Miller)
In-reply-to: <3AA60A35.F7C70C1@xxxxxxxxxx> from "Andrew Morton" at Mar 7, 1 09:15:17 pm
Sender: owner-netdev@xxxxxxxxxxx
Hello!

> So you're saying that you can reproduce this crash with acenic?

Yes, I found capital logical bug there. Evictor on smp can corrupt queues.
Shame on me, I _knew_ that this pattern is wrong, socket hash tables need
the same, but they are right. So, fix is to work like sockets.

Patch is appended. Please, test.

Alexey



--- ../vger3-010306/linux/net/ipv4/ip_fragment.c        Wed Dec 20 22:31:50 2000
+++ linux/net/ipv4/ip_fragment.c        Wed Mar  7 18:52:45 2001
@@ -214,18 +214,17 @@
                        if (ipq_hash[i] == NULL)
                                continue;
 
-                       write_lock(&ipfrag_lock);
+                       read_lock(&ipfrag_lock);
                        if ((qp = ipq_hash[i]) != NULL) {
                                /* find the oldest queue for this hash bucket */
                                while (qp->next)
                                        qp = qp->next;
-                               __ipq_unlink(qp);
-                               write_unlock(&ipfrag_lock);
+                               atomic_inc(&qp->refcnt);
+                               read_unlock(&ipfrag_lock);
 
                                spin_lock(&qp->lock);
-                               if (del_timer(&qp->timer))
-                                       atomic_dec(&qp->refcnt);
-                               qp->last_in |= COMPLETE;
+                               if (!(qp->last_in&COMPLETE))
+                                       ipq_kill(qp);
                                spin_unlock(&qp->lock);
 
                                ipq_put(qp);
@@ -233,7 +232,7 @@
                                progress = 1;
                                continue;
                        }
-                       write_unlock(&ipfrag_lock);
+                       read_unlock(&ipfrag_lock);
                }
        } while (progress);
 }
--- ../vger3-010306/linux/net/ipv6/reassembly.c Sat Jan 13 21:29:44 2001
+++ linux/net/ipv6/reassembly.c Wed Mar  7 18:52:46 2001
@@ -204,18 +204,17 @@
                        if (ip6_frag_hash[i] == NULL)
                                continue;
 
-                       write_lock(&ip6_frag_lock);
+                       read_lock(&ip6_frag_lock);
                        if ((fq = ip6_frag_hash[i]) != NULL) {
                                /* find the oldest queue for this hash bucket */
                                while (fq->next)
                                        fq = fq->next;
-                               __fq_unlink(fq);
-                               write_unlock(&ip6_frag_lock);
+                               atomic_inc(&fq->refcnt);
+                               read_unlock(&ip6_frag_lock);
 
                                spin_lock(&fq->lock);
-                               if (del_timer(&fq->timer))
-                                       atomic_dec(&fq->refcnt);
-                               fq->last_in |= COMPLETE;
+                               if (!(fq->last_in&COMPLETE))
+                                       fq_kill(fq);
                                spin_unlock(&fq->lock);
 
                                fq_put(fq);
@@ -223,7 +222,7 @@
                                progress = 1;
                                continue;
                        }
-                       write_unlock(&ip6_frag_lock);
+                       read_unlock(&ip6_frag_lock);
                }
        } while (progress);
 }

<Prev in Thread] Current Thread [Next in Thread>