[IPV4] fib_trie: avoid extra search on delete
Get rid of extra search that made route deletion O(n). Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a88ee22925
commit
9195bef7fb
1 changed files with 12 additions and 38 deletions
|
@ -1545,49 +1545,23 @@ static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* only called from updater side */
|
||||
static int trie_leaf_remove(struct trie *t, t_key key)
|
||||
/*
|
||||
* Remove the leaf and return parent.
|
||||
*/
|
||||
static void trie_leaf_remove(struct trie *t, struct leaf *l)
|
||||
{
|
||||
t_key cindex;
|
||||
struct tnode *tp = NULL;
|
||||
struct node *n = t->trie;
|
||||
struct leaf *l;
|
||||
struct tnode *tp = node_parent((struct node *) l);
|
||||
|
||||
pr_debug("entering trie_leaf_remove(%p)\n", n);
|
||||
|
||||
/* Note that in the case skipped bits, those bits are *not* checked!
|
||||
* When we finish this, we will have NULL or a T_LEAF, and the
|
||||
* T_LEAF may or may not match our key.
|
||||
*/
|
||||
|
||||
while (n != NULL && IS_TNODE(n)) {
|
||||
struct tnode *tn = (struct tnode *) n;
|
||||
check_tnode(tn);
|
||||
n = tnode_get_child(tn, tkey_extract_bits(key,
|
||||
tn->pos, tn->bits));
|
||||
|
||||
BUG_ON(n && node_parent(n) != tn);
|
||||
}
|
||||
l = (struct leaf *) n;
|
||||
|
||||
if (!n || !tkey_equals(l->key, key))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Key found.
|
||||
* Remove the leaf and rebalance the tree
|
||||
*/
|
||||
tp = node_parent(n);
|
||||
tnode_free((struct tnode *) n);
|
||||
pr_debug("entering trie_leaf_remove(%p)\n", l);
|
||||
|
||||
if (tp) {
|
||||
cindex = tkey_extract_bits(key, tp->pos, tp->bits);
|
||||
t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits);
|
||||
put_child(t, (struct tnode *)tp, cindex, NULL);
|
||||
rcu_assign_pointer(t->trie, trie_rebalance(t, tp));
|
||||
} else
|
||||
rcu_assign_pointer(t->trie, NULL);
|
||||
|
||||
return 1;
|
||||
tnode_free((struct tnode *) l);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1665,7 +1639,7 @@ static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
|
|||
}
|
||||
|
||||
if (hlist_empty(&l->list))
|
||||
trie_leaf_remove(t, key);
|
||||
trie_leaf_remove(t, l);
|
||||
|
||||
if (fa->fa_state & FA_S_ACCESSED)
|
||||
rt_cache_flush(-1);
|
||||
|
@ -1778,19 +1752,19 @@ static struct leaf *trie_nextleaf(struct leaf *l)
|
|||
static int fn_trie_flush(struct fib_table *tb)
|
||||
{
|
||||
struct trie *t = (struct trie *) tb->tb_data;
|
||||
struct leaf *ll = NULL, *l = NULL;
|
||||
struct leaf *l, *ll = NULL;
|
||||
int found = 0;
|
||||
|
||||
for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) {
|
||||
found += trie_flush_leaf(t, l);
|
||||
|
||||
if (ll && hlist_empty(&ll->list))
|
||||
trie_leaf_remove(t, ll->key);
|
||||
trie_leaf_remove(t, ll);
|
||||
ll = l;
|
||||
}
|
||||
|
||||
if (ll && hlist_empty(&ll->list))
|
||||
trie_leaf_remove(t, ll->key);
|
||||
trie_leaf_remove(t, ll);
|
||||
|
||||
pr_debug("trie_flush found=%d\n", found);
|
||||
return found;
|
||||
|
|
Loading…
Reference in a new issue