aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Olsson <robert.olsson@its.uu.se>2005-07-05 18:02:40 -0400
committerDavid S. Miller <davem@davemloft.net>2005-07-05 18:02:40 -0400
commit2f36895aa774cf4d1c3d68921e0209e796b66600 (patch)
tree7b437fbf829fae6b29b74fa276ae1adea435a917
parentdb1322b8012e1a8ad711c04813817328cff46718 (diff)
[IPV4]: More broken memory allocation fixes for fib_trie
Below a patch to preallocate memory when doing resize of trie (inflate halve) If preallocations fails it just skips the resize of this tnode for this time. The oops we got when killing bgpd (with full routing) is now gone. Patrick memory patch is also used. Signed-off-by: Robert Olsson <robert.olsson@its.uu.se> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/fib_trie.c177
1 files changed, 145 insertions, 32 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 9038b914b4b1..4be234c7d8c3 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -43,7 +43,7 @@
43 * 2 of the License, or (at your option) any later version. 43 * 2 of the License, or (at your option) any later version.
44 */ 44 */
45 45
46#define VERSION "0.324" 46#define VERSION "0.325"
47 47
48#include <linux/config.h> 48#include <linux/config.h>
49#include <asm/uaccess.h> 49#include <asm/uaccess.h>
@@ -136,6 +136,7 @@ struct trie_use_stats {
136 unsigned int semantic_match_passed; 136 unsigned int semantic_match_passed;
137 unsigned int semantic_match_miss; 137 unsigned int semantic_match_miss;
138 unsigned int null_node_hit; 138 unsigned int null_node_hit;
139 unsigned int resize_node_skipped;
139}; 140};
140#endif 141#endif
141 142
@@ -164,8 +165,8 @@ static void put_child(struct trie *t, struct tnode *tn, int i, struct node *n);
164static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull); 165static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull);
165static int tnode_child_length(struct tnode *tn); 166static int tnode_child_length(struct tnode *tn);
166static struct node *resize(struct trie *t, struct tnode *tn); 167static struct node *resize(struct trie *t, struct tnode *tn);
167static struct tnode *inflate(struct trie *t, struct tnode *tn); 168static struct tnode *inflate(struct trie *t, struct tnode *tn, int *err);
168static struct tnode *halve(struct trie *t, struct tnode *tn); 169static struct tnode *halve(struct trie *t, struct tnode *tn, int *err);
169static void tnode_free(struct tnode *tn); 170static void tnode_free(struct tnode *tn);
170static void trie_dump_seq(struct seq_file *seq, struct trie *t); 171static void trie_dump_seq(struct seq_file *seq, struct trie *t);
171extern struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio); 172extern struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio);
@@ -481,6 +482,7 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int w
481static struct node *resize(struct trie *t, struct tnode *tn) 482static struct node *resize(struct trie *t, struct tnode *tn)
482{ 483{
483 int i; 484 int i;
485 int err = 0;
484 486
485 if (!tn) 487 if (!tn)
486 return NULL; 488 return NULL;
@@ -577,12 +579,20 @@ static struct node *resize(struct trie *t, struct tnode *tn)
577 */ 579 */
578 580
579 check_tnode(tn); 581 check_tnode(tn);
580 582
583 err = 0;
581 while ((tn->full_children > 0 && 584 while ((tn->full_children > 0 &&
582 50 * (tn->full_children + tnode_child_length(tn) - tn->empty_children) >= 585 50 * (tn->full_children + tnode_child_length(tn) - tn->empty_children) >=
583 inflate_threshold * tnode_child_length(tn))) { 586 inflate_threshold * tnode_child_length(tn))) {
584 587
585 tn = inflate(t, tn); 588 tn = inflate(t, tn, &err);
589
590 if(err) {
591#ifdef CONFIG_IP_FIB_TRIE_STATS
592 t->stats.resize_node_skipped++;
593#endif
594 break;
595 }
586 } 596 }
587 597
588 check_tnode(tn); 598 check_tnode(tn);
@@ -591,11 +601,22 @@ static struct node *resize(struct trie *t, struct tnode *tn)
591 * Halve as long as the number of empty children in this 601 * Halve as long as the number of empty children in this
592 * node is above threshold. 602 * node is above threshold.
593 */ 603 */
604
605 err = 0;
594 while (tn->bits > 1 && 606 while (tn->bits > 1 &&
595 100 * (tnode_child_length(tn) - tn->empty_children) < 607 100 * (tnode_child_length(tn) - tn->empty_children) <
596 halve_threshold * tnode_child_length(tn)) 608 halve_threshold * tnode_child_length(tn)) {
609
610 tn = halve(t, tn, &err);
611
612 if(err) {
613#ifdef CONFIG_IP_FIB_TRIE_STATS
614 t->stats.resize_node_skipped++;
615#endif
616 break;
617 }
618 }
597 619
598 tn = halve(t, tn);
599 620
600 /* Only one child remains */ 621 /* Only one child remains */
601 622
@@ -620,7 +641,7 @@ static struct node *resize(struct trie *t, struct tnode *tn)
620 return (struct node *) tn; 641 return (struct node *) tn;
621} 642}
622 643
623static struct tnode *inflate(struct trie *t, struct tnode *tn) 644static struct tnode *inflate(struct trie *t, struct tnode *tn, int *err)
624{ 645{
625 struct tnode *inode; 646 struct tnode *inode;
626 struct tnode *oldtnode = tn; 647 struct tnode *oldtnode = tn;
@@ -632,8 +653,63 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
632 653
633 tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1); 654 tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1);
634 655
635 if (!tn) 656 if (!tn) {
636 trie_bug("tnode_new failed"); 657 *err = -ENOMEM;
658 return oldtnode;
659 }
660
661 /*
662 * Preallocate and store tnodes before the actual work so we
663 * don't get into an inconsistent state if memory allocation
664 * fails. In case of failure we return the oldnode and inflate
665 * of tnode is ignored.
666 */
667
668 for(i = 0; i < olen; i++) {
669 struct tnode *inode = (struct tnode *) tnode_get_child(oldtnode, i);
670
671 if (inode &&
672 IS_TNODE(inode) &&
673 inode->pos == oldtnode->pos + oldtnode->bits &&
674 inode->bits > 1) {
675 struct tnode *left, *right;
676
677 t_key m = TKEY_GET_MASK(inode->pos, 1);
678
679 left = tnode_new(inode->key&(~m), inode->pos + 1,
680 inode->bits - 1);
681
682 if(!left) {
683 *err = -ENOMEM;
684 break;
685 }
686
687 right = tnode_new(inode->key|m, inode->pos + 1,
688 inode->bits - 1);
689
690 if(!right) {
691 *err = -ENOMEM;
692 break;
693 }
694
695 put_child(t, tn, 2*i, (struct node *) left);
696 put_child(t, tn, 2*i+1, (struct node *) right);
697 }
698 }
699
700 if(*err) {
701 int size = tnode_child_length(tn);
702 int j;
703
704 for(j = 0; j < size; j++)
705 if( tn->child[j])
706 tnode_free((struct tnode *)tn->child[j]);
707
708 tnode_free(tn);
709
710 *err = -ENOMEM;
711 return oldtnode;
712 }
637 713
638 for(i = 0; i < olen; i++) { 714 for(i = 0; i < olen; i++) {
639 struct node *node = tnode_get_child(oldtnode, i); 715 struct node *node = tnode_get_child(oldtnode, i);
@@ -646,7 +722,7 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
646 722
647 if(IS_LEAF(node) || ((struct tnode *) node)->pos > 723 if(IS_LEAF(node) || ((struct tnode *) node)->pos >
648 tn->pos + tn->bits - 1) { 724 tn->pos + tn->bits - 1) {
649 if(tkey_extract_bits(node->key, tn->pos + tn->bits - 1, 725 if(tkey_extract_bits(node->key, oldtnode->pos + oldtnode->bits,
650 1) == 0) 726 1) == 0)
651 put_child(t, tn, 2*i, node); 727 put_child(t, tn, 2*i, node);
652 else 728 else
@@ -686,27 +762,22 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
686 * the position (inode->pos) 762 * the position (inode->pos)
687 */ 763 */
688 764
689 t_key m = TKEY_GET_MASK(inode->pos, 1);
690
691 /* Use the old key, but set the new significant 765 /* Use the old key, but set the new significant
692 * bit to zero. 766 * bit to zero.
693 */ 767 */
694 left = tnode_new(inode->key&(~m), inode->pos + 1,
695 inode->bits - 1);
696 768
697 if(!left) 769 left = (struct tnode *) tnode_get_child(tn, 2*i);
698 trie_bug("tnode_new failed"); 770 put_child(t, tn, 2*i, NULL);
699 771
700 772 if(!left)
701 /* Use the old key, but set the new significant 773 BUG();
702 * bit to one. 774
703 */ 775 right = (struct tnode *) tnode_get_child(tn, 2*i+1);
704 right = tnode_new(inode->key|m, inode->pos + 1, 776 put_child(t, tn, 2*i+1, NULL);
705 inode->bits - 1); 777
778 if(!right)
779 BUG();
706 780
707 if(!right)
708 trie_bug("tnode_new failed");
709
710 size = tnode_child_length(left); 781 size = tnode_child_length(left);
711 for(j = 0; j < size; j++) { 782 for(j = 0; j < size; j++) {
712 put_child(t, left, j, inode->child[j]); 783 put_child(t, left, j, inode->child[j]);
@@ -722,7 +793,7 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
722 return tn; 793 return tn;
723} 794}
724 795
725static struct tnode *halve(struct trie *t, struct tnode *tn) 796static struct tnode *halve(struct trie *t, struct tnode *tn, int *err)
726{ 797{
727 struct tnode *oldtnode = tn; 798 struct tnode *oldtnode = tn;
728 struct node *left, *right; 799 struct node *left, *right;
@@ -733,8 +804,48 @@ static struct tnode *halve(struct trie *t, struct tnode *tn)
733 804
734 tn=tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1); 805 tn=tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1);
735 806
736 if(!tn) 807 if (!tn) {
737 trie_bug("tnode_new failed"); 808 *err = -ENOMEM;
809 return oldtnode;
810 }
811
812 /*
813 * Preallocate and store tnodes before the actual work so we
814 * don't get into an inconsistent state if memory allocation
815 * fails. In case of failure we return the oldnode and halve
816 * of tnode is ignored.
817 */
818
819 for(i = 0; i < olen; i += 2) {
820 left = tnode_get_child(oldtnode, i);
821 right = tnode_get_child(oldtnode, i+1);
822
823 /* Two nonempty children */
824 if( left && right) {
825 struct tnode *newBinNode =
826 tnode_new(left->key, tn->pos + tn->bits, 1);
827
828 if(!newBinNode) {
829 *err = -ENOMEM;
830 break;
831 }
832 put_child(t, tn, i/2, (struct node *)newBinNode);
833 }
834 }
835
836 if(*err) {
837 int size = tnode_child_length(tn);
838 int j;
839
840 for(j = 0; j < size; j++)
841 if( tn->child[j])
842 tnode_free((struct tnode *)tn->child[j]);
843
844 tnode_free(tn);
845
846 *err = -ENOMEM;
847 return oldtnode;
848 }
738 849
739 for(i = 0; i < olen; i += 2) { 850 for(i = 0; i < olen; i += 2) {
740 left = tnode_get_child(oldtnode, i); 851 left = tnode_get_child(oldtnode, i);
@@ -751,10 +862,11 @@ static struct tnode *halve(struct trie *t, struct tnode *tn)
751 /* Two nonempty children */ 862 /* Two nonempty children */
752 else { 863 else {
753 struct tnode *newBinNode = 864 struct tnode *newBinNode =
754 tnode_new(left->key, tn->pos + tn->bits, 1); 865 (struct tnode *) tnode_get_child(tn, i/2);
866 put_child(t, tn, i/2, NULL);
755 867
756 if(!newBinNode) 868 if(!newBinNode)
757 trie_bug("tnode_new failed"); 869 BUG();
758 870
759 put_child(t, newBinNode, 0, left); 871 put_child(t, newBinNode, 0, left);
760 put_child(t, newBinNode, 1, right); 872 put_child(t, newBinNode, 1, right);
@@ -2322,6 +2434,7 @@ static void collect_and_show(struct trie *t, struct seq_file *seq)
2322 seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed); 2434 seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed);
2323 seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss); 2435 seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss);
2324 seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit); 2436 seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit);
2437 seq_printf(seq,"skipped node resize = %d\n", t->stats.resize_node_skipped);
2325#ifdef CLEAR_STATS 2438#ifdef CLEAR_STATS
2326 memset(&(t->stats), 0, sizeof(t->stats)); 2439 memset(&(t->stats), 0, sizeof(t->stats));
2327#endif 2440#endif