]> err.no Git - linux-2.6/blobdiff - net/dccp/ackvec.c
[DCCP] Ackvec: fix soft lockup in ackvec handling code
[linux-2.6] / net / dccp / ackvec.c
index b4ff14f3d4f886e9c990187fe0e36adc2e1ac0d6..8c211c58893b2a6de115110743ed33a88befbe4d 100644 (file)
@@ -81,15 +81,16 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
        if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
                return -1;
 
-       avr = dccp_ackvec_record_new();
-       if (avr == NULL)
-               return -1;
-
        dccp_timestamp(sk, &now);
        elapsed_time = timeval_delta(&now, &av->dccpav_time) / 10;
 
-       if (elapsed_time != 0)
-               dccp_insert_option_elapsed_time(sk, skb, elapsed_time);
+       if (elapsed_time != 0 &&
+           dccp_insert_option_elapsed_time(sk, skb, elapsed_time))
+               return -1;
+
+       avr = dccp_ackvec_record_new();
+       if (avr == NULL)
+               return -1;
 
        DCCP_SKB_CB(skb)->dccpd_opt_len += len;
 
@@ -159,7 +160,17 @@ void dccp_ackvec_free(struct dccp_ackvec *av)
 {
        if (unlikely(av == NULL))
                return;
-       WARN_ON(!list_empty(&av->dccpav_records));
+
+       if (!list_empty(&av->dccpav_records)) {
+               struct dccp_ackvec_record *avr, *next;
+
+               list_for_each_entry_safe(avr, next, &av->dccpav_records,
+                                        dccpavr_node) {
+                       list_del_init(&avr->dccpavr_node);
+                       dccp_ackvec_record_delete(avr);
+               }
+       }
+
        kmem_cache_free(dccp_ackvec_slab, av);
 }
 
@@ -300,7 +311,6 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
        av->dccpav_buf_ackno = ackno;
        dccp_timestamp(sk, &av->dccpav_time);
 out:
-       dccp_pr_debug("");
        return 0;
 
 out_duplicate:
@@ -442,6 +452,7 @@ found:
                                              (unsigned long long)
                                              avr->dccpavr_ack_ackno);
                                dccp_ackvec_throw_record(av, avr);
+                               break;
                        }
                        /*
                         * If it wasn't received, continue scanning... we might