Re: ipfrag_lock related lockup

From: Andi Kleen (ak@suse.de)
Date: Wed Jun 21 2000 - 14:17:11 EST


On Wed, Jun 21, 2000 at 05:08:15PM +0200, Andreas Ehliar wrote:
> (gdb) x/5i 0xc024cbb0
> 0xc024cbb0 <stext_lock+24024>: cmpb $0x0,0xc02e342c
> 0xc024cbb7 <stext_lock+24031>: repz nop
> 0xc024cbb9 <stext_lock+24033>: jle 0xc024cbb0 <stext_lock+24024>
> 0xc024cbbb <stext_lock+24035>: jmp 0xc020e763 <ip_defrag+43>
> 0xc024cbc0 <stext_lock+24040>: call 0xc010ac84 <__read_lock_failed>
> (gdb) x/5i 0xc020e763
> 0xc020e763 <ip_defrag+43>: lock decb 0xc02e342c
> 0xc020e76a <ip_defrag+50>: js 0xc024cbb0 <stext_lock+24024>
> 0xc020e770 <ip_defrag+56>: mov 0xc02e3430,%eax
> 0xc020e775 <ip_defrag+61>: cmp 0xc02e3420,%eax
> 0xc020e77b <ip_defrag+67>: jle 0xc020e782 <ip_defrag+74>

Looks like a netfilter bug. ip_defrag assumes that it is only called
from softirq context, but netfilter conntracking calls it from LOCAL_OUT
in process context.

Could you try the following patch? It makes ip_defrag safe to use in
process context. Another possible (probably cheaper) fix would be to
do a local_bh_disable() around the ip_defrag in ip_conntrack_core.

-Andi

--- linux/net/ipv4/ip_fragment.c-bhfrag Sat May 27 16:53:40 2000
+++ linux/net/ipv4/ip_fragment.c Wed Jun 21 21:07:53 2000
@@ -201,7 +201,7 @@
 {
         struct ipq *qp = (struct ipq *) arg;
 
- spin_lock(&ipfrag_lock);
+ spin_lock_bh(&ipfrag_lock);
           if(!qp->fragments)
         {
 #ifdef IP_EXPIRE_DEBUG
@@ -218,7 +218,7 @@
 out:
         /* Nuke the fragment queue. */
         ip_free(qp);
- spin_unlock(&ipfrag_lock);
+ spin_unlock_bh(&ipfrag_lock);
 }
 
 /* Memory limiting on fragments. Evictor trashes the oldest
@@ -435,7 +435,7 @@
         
         IP_INC_STATS_BH(IpReasmReqds);
 
- spin_lock(&ipfrag_lock);
+ spin_lock_bh(&ipfrag_lock);
 
         /* Start by cleaning up the memory. */
         if (atomic_read(&ip_frag_mem) > sysctl_ipfrag_high_thresh)
@@ -581,7 +581,7 @@
 out_freequeue:
                 ip_free(qp);
 out_skb:
- spin_unlock(&ipfrag_lock);
+ spin_unlock_bh(&ipfrag_lock);
                 return skb;
         }
 
@@ -591,7 +591,7 @@
 out_timer:
         mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time); /* ~ 30 seconds */
 out:
- spin_unlock(&ipfrag_lock);
+ spin_unlock_bh(&ipfrag_lock);
         return NULL;
 
         /*

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Jun 23 2000 - 21:00:22 EST