提交 82cfbb00 编写于 作者: S Stephen Hemminger 提交者: David S. Miller

[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: NStephen Hemminger <shemminger@vyatta.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 64347f78
...@@ -1711,64 +1711,65 @@ static int trie_flush_leaf(struct trie *t, struct leaf *l) ...@@ -1711,64 +1711,65 @@ static int trie_flush_leaf(struct trie *t, struct leaf *l)
return found; return found;
} }
/* rcu_read_lock needs to be hold by caller from readside */ /*
* Scan for the next right leaf starting at node p->child[idx]
static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf) * Since we have back pointer, no recursion necessary.
*/
static struct leaf *leaf_walk_rcu(struct tnode *p, struct node *c)
{ {
struct node *c = (struct node *) thisleaf; do {
struct tnode *p; t_key idx;
int idx;
struct node *trie = rcu_dereference(t->trie);
if (c == NULL) {
if (trie == NULL)
return NULL;
if (IS_LEAF(trie)) /* trie w. just a leaf */
return (struct leaf *) trie;
p = (struct tnode *)trie; /* Start */
} else
p = node_parent_rcu(c);
while (p) {
int pos, last;
/* Find the next child of the parent */
if (c) if (c)
pos = 1 + tkey_extract_bits(c->key, p->pos, p->bits); idx = tkey_extract_bits(c->key, p->pos, p->bits) + 1;
else else
pos = 0; idx = 0;
last = 1 << p->bits;
for (idx = pos; idx < last ; idx++) {
c = rcu_dereference(p->child[idx]);
while (idx < 1u << p->bits) {
c = tnode_get_child_rcu(p, idx++);
if (!c) if (!c)
continue; continue;
/* Decend if tnode */ if (IS_LEAF(c)) {
while (IS_TNODE(c)) { prefetch(p->child[idx]);
p = (struct tnode *) c; return (struct leaf *) c;
idx = 0;
/* Rightmost non-NULL branch */
if (p && IS_TNODE(p))
while (!(c = rcu_dereference(p->child[idx]))
&& idx < (1<<p->bits)) idx++;
/* Done with this tnode? */
if (idx >= (1 << p->bits) || !c)
goto up;
} }
return (struct leaf *) c;
/* Rescan start scanning in new node */
p = (struct tnode *) c;
idx = 0;
} }
up:
/* No more children go up one step */ /* Node empty, walk back up to parent */
c = (struct node *) p; c = (struct node *) p;
p = node_parent_rcu(c); } while ( (p = node_parent_rcu(c)) != NULL);
}
return NULL; /* Ready. Root of trie */ return NULL; /* Root of trie */
}
static struct leaf *trie_firstleaf(struct trie *t)
{
struct tnode *n = (struct tnode *) rcu_dereference(t->trie);
if (!n)
return NULL;
if (IS_LEAF(n)) /* trie is just a leaf */
return (struct leaf *) n;
return leaf_walk_rcu(n, NULL);
}
static struct leaf *trie_nextleaf(struct leaf *l)
{
struct node *c = (struct node *) l;
struct tnode *p = node_parent(c);
if (!p)
return NULL; /* trie with just one leaf */
return leaf_walk_rcu(p, c);
} }
/* /*
...@@ -1778,9 +1779,9 @@ static int fn_trie_flush(struct fib_table *tb) ...@@ -1778,9 +1779,9 @@ static int fn_trie_flush(struct fib_table *tb)
{ {
struct trie *t = (struct trie *) tb->tb_data; struct trie *t = (struct trie *) tb->tb_data;
struct leaf *ll = NULL, *l = NULL; struct leaf *ll = NULL, *l = NULL;
int found = 0, h; int found = 0;
for (h = 0; (l = nextleaf(t, l)) != NULL; h++) { for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) {
found += trie_flush_leaf(t, l); found += trie_flush_leaf(t, l);
if (ll && hlist_empty(&ll->list)) 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,7 +1888,6 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah,
i++; i++;
continue; continue;
} }
BUG_ON(!fa->fa_info);
if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid, if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, cb->nlh->nlmsg_seq,
...@@ -1916,8 +1916,9 @@ static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb, ...@@ -1916,8 +1916,9 @@ static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb,
struct leaf *l = NULL; struct leaf *l = NULL;
s_h = cb->args[3]; s_h = cb->args[3];
h = 0;
for (h = 0; (l = nextleaf(t, l)) != NULL; h++) { for (l = trie_firstleaf(t); l != NULL; h++, l = trie_nextleaf(l)) {
if (h < s_h) if (h < s_h)
continue; continue;
if (h > s_h) if (h > s_h)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册