diff options
author | Stephen Hemminger <stephen.hemminger@vyatta.com> | 2008-01-23 00:55:32 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:10:59 -0500 |
commit | 82cfbb008572b1a953091ef78f767aa3ca213092 (patch) | |
tree | 1e2ef11b188e89dd41b28b20580b2c424d75e9bd /net/ipv4/fib_trie.c | |
parent | 64347f786d13349d6a6f812f3a83c269e26c0136 (diff) |
[IPV4] fib_trie: iterator recode
Remove the complex loop structure of nextleaf() and replace it with a
simpler tree walker. This improves the performance and is much
cleaner.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/fib_trie.c')
-rw-r--r-- | net/ipv4/fib_trie.c | 103 |
1 files changed, 52 insertions, 51 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 41264695039a..dab439b52672 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -1711,64 +1711,65 @@ static int trie_flush_leaf(struct trie *t, struct leaf *l) | |||
1711 | return found; | 1711 | return found; |
1712 | } | 1712 | } |
1713 | 1713 | ||
1714 | /* rcu_read_lock needs to be hold by caller from readside */ | 1714 | /* |
1715 | 1715 | * Scan for the next right leaf starting at node p->child[idx] | |
1716 | static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf) | 1716 | * Since we have back pointer, no recursion necessary. |
1717 | */ | ||
1718 | static struct leaf *leaf_walk_rcu(struct tnode *p, struct node *c) | ||
1717 | { | 1719 | { |
1718 | struct node *c = (struct node *) thisleaf; | 1720 | do { |
1719 | struct tnode *p; | 1721 | t_key idx; |
1720 | int idx; | ||
1721 | struct node *trie = rcu_dereference(t->trie); | ||
1722 | 1722 | ||
1723 | if (c == NULL) { | ||
1724 | if (trie == NULL) | ||
1725 | return NULL; | ||
1726 | |||
1727 | if (IS_LEAF(trie)) /* trie w. just a leaf */ | ||
1728 | return (struct leaf *) trie; | ||
1729 | |||
1730 | p = (struct tnode *)trie; /* Start */ | ||
1731 | } else | ||
1732 | p = node_parent_rcu(c); | ||
1733 | |||
1734 | while (p) { | ||
1735 | int pos, last; | ||
1736 | |||
1737 | /* Find the next child of the parent */ | ||
1738 | if (c) | 1723 | if (c) |
1739 | pos = 1 + tkey_extract_bits(c->key, p->pos, p->bits); | 1724 | idx = tkey_extract_bits(c->key, p->pos, p->bits) + 1; |
1740 | else | 1725 | else |
1741 | pos = 0; | 1726 | idx = 0; |
1742 | |||
1743 | last = 1 << p->bits; | ||
1744 | for (idx = pos; idx < last ; idx++) { | ||
1745 | c = rcu_dereference(p->child[idx]); | ||
1746 | 1727 | ||
1728 | while (idx < 1u << p->bits) { | ||
1729 | c = tnode_get_child_rcu(p, idx++); | ||
1747 | if (!c) | 1730 | if (!c) |
1748 | continue; | 1731 | continue; |
1749 | 1732 | ||
1750 | /* Decend if tnode */ | 1733 | if (IS_LEAF(c)) { |
1751 | while (IS_TNODE(c)) { | 1734 | prefetch(p->child[idx]); |
1752 | p = (struct tnode *) c; | 1735 | return (struct leaf *) c; |
1753 | idx = 0; | ||
1754 | |||
1755 | /* Rightmost non-NULL branch */ | ||
1756 | if (p && IS_TNODE(p)) | ||
1757 | while (!(c = rcu_dereference(p->child[idx])) | ||
1758 | && idx < (1<<p->bits)) idx++; | ||
1759 | |||
1760 | /* Done with this tnode? */ | ||
1761 | if (idx >= (1 << p->bits) || !c) | ||
1762 | goto up; | ||
1763 | } | 1736 | } |
1764 | return (struct leaf *) c; | 1737 | |
1738 | /* Rescan start scanning in new node */ | ||
1739 | p = (struct tnode *) c; | ||
1740 | idx = 0; | ||
1765 | } | 1741 | } |
1766 | up: | 1742 | |
1767 | /* No more children go up one step */ | 1743 | /* Node empty, walk back up to parent */ |
1768 | c = (struct node *) p; | 1744 | c = (struct node *) p; |
1769 | p = node_parent_rcu(c); | 1745 | } while ( (p = node_parent_rcu(c)) != NULL); |
1770 | } | 1746 | |
1771 | return NULL; /* Ready. Root of trie */ | 1747 | return NULL; /* Root of trie */ |
1748 | } | ||
1749 | |||
1750 | |||
1751 | static struct leaf *trie_firstleaf(struct trie *t) | ||
1752 | { | ||
1753 | struct tnode *n = (struct tnode *) rcu_dereference(t->trie); | ||
1754 | |||
1755 | if (!n) | ||
1756 | return NULL; | ||
1757 | |||
1758 | if (IS_LEAF(n)) /* trie is just a leaf */ | ||
1759 | return (struct leaf *) n; | ||
1760 | |||
1761 | return leaf_walk_rcu(n, NULL); | ||
1762 | } | ||
1763 | |||
1764 | static struct leaf *trie_nextleaf(struct leaf *l) | ||
1765 | { | ||
1766 | struct node *c = (struct node *) l; | ||
1767 | struct tnode *p = node_parent(c); | ||
1768 | |||
1769 | if (!p) | ||
1770 | return NULL; /* trie with just one leaf */ | ||
1771 | |||
1772 | return leaf_walk_rcu(p, c); | ||
1772 | } | 1773 | } |
1773 | 1774 | ||
1774 | /* | 1775 | /* |
@@ -1778,9 +1779,9 @@ static int fn_trie_flush(struct fib_table *tb) | |||
1778 | { | 1779 | { |
1779 | struct trie *t = (struct trie *) tb->tb_data; | 1780 | struct trie *t = (struct trie *) tb->tb_data; |
1780 | struct leaf *ll = NULL, *l = NULL; | 1781 | struct leaf *ll = NULL, *l = NULL; |
1781 | int found = 0, h; | 1782 | int found = 0; |
1782 | 1783 | ||
1783 | for (h = 0; (l = nextleaf(t, l)) != NULL; h++) { | 1784 | for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) { |
1784 | found += trie_flush_leaf(t, l); | 1785 | found += trie_flush_leaf(t, l); |
1785 | 1786 | ||
1786 | if (ll && hlist_empty(&ll->list)) | 1787 | if (ll && hlist_empty(&ll->list)) |
@@ -1887,7 +1888,6 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, | |||
1887 | i++; | 1888 | i++; |
1888 | continue; | 1889 | continue; |
1889 | } | 1890 | } |
1890 | BUG_ON(!fa->fa_info); | ||
1891 | 1891 | ||
1892 | if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid, | 1892 | if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid, |
1893 | cb->nlh->nlmsg_seq, | 1893 | cb->nlh->nlmsg_seq, |
@@ -1916,8 +1916,9 @@ static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb, | |||
1916 | struct leaf *l = NULL; | 1916 | struct leaf *l = NULL; |
1917 | 1917 | ||
1918 | s_h = cb->args[3]; | 1918 | s_h = cb->args[3]; |
1919 | h = 0; | ||
1919 | 1920 | ||
1920 | for (h = 0; (l = nextleaf(t, l)) != NULL; h++) { | 1921 | for (l = trie_firstleaf(t); l != NULL; h++, l = trie_nextleaf(l)) { |
1921 | if (h < s_h) | 1922 | if (h < s_h) |
1922 | continue; | 1923 | continue; |
1923 | if (h > s_h) | 1924 | if (h > s_h) |