[IPV4]: Broken memory allocation in fib_trie
authorRobert Olsson <robert.olsson@its.uu.se>
Tue, 28 Jun 2005 22:00:39 +0000 (15:00 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 28 Jun 2005 22:00:39 +0000 (15:00 -0700)
This should help up the insertion... but the resize is more crucial.
and complex and needs some thinking.

Signed-off-by: Robert Olsson <robert.olsson@its.uu.se>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/fib_trie.c

index 0671569ee6f0e9ef1e824722930c47e22f64f4f1..b56e88edf1b351a10a8d83a0abf0a20f4c663e29 100644 (file)
@@ -43,7 +43,7 @@
  *             2 of the License, or (at your option) any later version.
  */
 
-#define VERSION "0.323"
+#define VERSION "0.324"
 
 #include <linux/config.h>
 #include <asm/uaccess.h>
@@ -341,8 +341,10 @@ static struct leaf *leaf_new(void)
 static struct leaf_info *leaf_info_new(int plen)
 {
        struct leaf_info *li = kmalloc(sizeof(struct leaf_info),  GFP_KERNEL);
-       li->plen = plen;
-       INIT_LIST_HEAD(&li->falh);
+       if(li) {
+               li->plen = plen;
+               INIT_LIST_HEAD(&li->falh);
+       }
        return li;
 }
 
@@ -879,8 +881,8 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
        return (struct node*) tn;
 }
 
-static struct list_head *
-fib_insert_node(struct trie *t, u32 key, int plen)
+static  struct list_head *
+fib_insert_node(struct trie *t, int *err, u32 key, int plen)
 {
        int pos, newpos;
        struct tnode *tp = NULL, *tn = NULL;
@@ -940,7 +942,6 @@ fib_insert_node(struct trie *t, u32 key, int plen)
        if(tp && IS_LEAF(tp))
                BUG();
 
-       t->revision++;
 
        /* Case 1: n is a leaf. Compare prefixes */
 
@@ -949,8 +950,10 @@ fib_insert_node(struct trie *t, u32 key, int plen)
                
                li = leaf_info_new(plen);
                
-               if(! li) 
-                       BUG();
+               if(! li) {
+                       *err = -ENOMEM;
+                       goto err;
+               }
 
                fa_head = &li->falh;
                insert_leaf_info(&l->list, li);
@@ -959,14 +962,19 @@ fib_insert_node(struct trie *t, u32 key, int plen)
        t->size++;
        l = leaf_new();
 
-       if(! l) 
-               BUG();
+       if(! l) {
+               *err = -ENOMEM;
+               goto err;
+       }
 
        l->key = key;
        li = leaf_info_new(plen);
 
-       if(! li) 
-               BUG();
+       if(! li) {
+               tnode_free((struct tnode *) l);
+               *err = -ENOMEM;
+               goto err;
+       }
 
        fa_head = &li->falh;
        insert_leaf_info(&l->list, li);
@@ -1003,9 +1011,14 @@ fib_insert_node(struct trie *t, u32 key, int plen)
                        newpos = 0;
                        tn = tnode_new(key, newpos, 1); /* First tnode */ 
                }
-               if(!tn) 
-                       trie_bug("tnode_pfx_new failed");
 
+               if(!tn) {
+                       free_leaf_info(li);
+                       tnode_free((struct tnode *) l);
+                       *err = -ENOMEM;
+                       goto err;
+               }                       
+                       
                NODE_SET_PARENT(tn, tp);
 
                missbit=tkey_extract_bits(key, newpos, 1);
@@ -1027,7 +1040,9 @@ fib_insert_node(struct trie *t, u32 key, int plen)
        }
        /* Rebalance the trie */
        t->trie = trie_rebalance(t, tp);
-done:;
+done:
+       t->revision++;
+err:;
        return fa_head;
 }
 
@@ -1156,8 +1171,12 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
         * Insert new entry to the list.
         */
 
-       if(!fa_head)
-               fa_head = fib_insert_node(t, key, plen);
+       if(!fa_head) {
+               fa_head = fib_insert_node(t, &err, key, plen);
+               err = 0;
+               if(err) 
+                       goto out_free_new_fa;
+       }
 
        write_lock_bh(&fib_lock);
 
@@ -1170,6 +1189,9 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
        rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, nlhdr, req);
 succeeded:
        return 0;
+
+out_free_new_fa:
+       kmem_cache_free(fn_alias_kmem, new_fa);
 out:
        fib_release_info(fi);
 err:;