Commit 8d8e810c authored by Alexander Duyck's avatar Alexander Duyck Committed by David S. Miller

fib_trie: Return pointer to tnode pointer in resize/inflate/halve

Resize related functions now all return a pointer to the pointer that
references the object that was resized.
Signed-off-by: default avatarAlexander Duyck <alexander.h.duyck@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 72be7260
...@@ -144,7 +144,7 @@ struct trie { ...@@ -144,7 +144,7 @@ struct trie {
#endif #endif
}; };
static void resize(struct trie *t, struct tnode *tn); static struct tnode **resize(struct trie *t, struct tnode *tn);
static size_t tnode_free_size; static size_t tnode_free_size;
/* /*
...@@ -468,9 +468,11 @@ static void tnode_free(struct tnode *tn) ...@@ -468,9 +468,11 @@ static void tnode_free(struct tnode *tn)
} }
} }
static void replace(struct trie *t, struct tnode *oldtnode, struct tnode *tn) static struct tnode __rcu **replace(struct trie *t, struct tnode *oldtnode,
struct tnode *tn)
{ {
struct tnode *tp = node_parent(oldtnode); struct tnode *tp = node_parent(oldtnode);
struct tnode **cptr;
unsigned long i; unsigned long i;
/* setup the parent pointer out of and back into this node */ /* setup the parent pointer out of and back into this node */
...@@ -483,6 +485,9 @@ static void replace(struct trie *t, struct tnode *oldtnode, struct tnode *tn) ...@@ -483,6 +485,9 @@ static void replace(struct trie *t, struct tnode *oldtnode, struct tnode *tn)
/* all pointers should be clean so we are done */ /* all pointers should be clean so we are done */
tnode_free(oldtnode); tnode_free(oldtnode);
/* record the pointer that is pointing to this node */
cptr = tp ? tp->tnode : &t->trie;
/* resize children now that oldtnode is freed */ /* resize children now that oldtnode is freed */
for (i = tnode_child_length(tn); i;) { for (i = tnode_child_length(tn); i;) {
struct tnode *inode = tnode_get_child(tn, --i); struct tnode *inode = tnode_get_child(tn, --i);
...@@ -491,9 +496,11 @@ static void replace(struct trie *t, struct tnode *oldtnode, struct tnode *tn) ...@@ -491,9 +496,11 @@ static void replace(struct trie *t, struct tnode *oldtnode, struct tnode *tn)
if (tnode_full(tn, inode)) if (tnode_full(tn, inode))
resize(t, inode); resize(t, inode);
} }
return cptr;
} }
static int inflate(struct trie *t, struct tnode *oldtnode) static struct tnode __rcu **inflate(struct trie *t, struct tnode *oldtnode)
{ {
struct tnode *tn; struct tnode *tn;
unsigned long i; unsigned long i;
...@@ -503,7 +510,7 @@ static int inflate(struct trie *t, struct tnode *oldtnode) ...@@ -503,7 +510,7 @@ static int inflate(struct trie *t, struct tnode *oldtnode)
tn = tnode_new(oldtnode->key, oldtnode->pos - 1, oldtnode->bits + 1); tn = tnode_new(oldtnode->key, oldtnode->pos - 1, oldtnode->bits + 1);
if (!tn) if (!tn)
return -ENOMEM; goto notnode;
/* prepare oldtnode to be freed */ /* prepare oldtnode to be freed */
tnode_free_init(oldtnode); tnode_free_init(oldtnode);
...@@ -580,16 +587,15 @@ static int inflate(struct trie *t, struct tnode *oldtnode) ...@@ -580,16 +587,15 @@ static int inflate(struct trie *t, struct tnode *oldtnode)
} }
/* setup the parent pointers into and out of this node */ /* setup the parent pointers into and out of this node */
replace(t, oldtnode, tn); return replace(t, oldtnode, tn);
return 0;
nomem: nomem:
/* all pointers should be clean so we are done */ /* all pointers should be clean so we are done */
tnode_free(tn); tnode_free(tn);
return -ENOMEM; notnode:
return NULL;
} }
static int halve(struct trie *t, struct tnode *oldtnode) static struct tnode __rcu **halve(struct trie *t, struct tnode *oldtnode)
{ {
struct tnode *tn; struct tnode *tn;
unsigned long i; unsigned long i;
...@@ -598,7 +604,7 @@ static int halve(struct trie *t, struct tnode *oldtnode) ...@@ -598,7 +604,7 @@ static int halve(struct trie *t, struct tnode *oldtnode)
tn = tnode_new(oldtnode->key, oldtnode->pos + 1, oldtnode->bits - 1); tn = tnode_new(oldtnode->key, oldtnode->pos + 1, oldtnode->bits - 1);
if (!tn) if (!tn)
return -ENOMEM; goto notnode;
/* prepare oldtnode to be freed */ /* prepare oldtnode to be freed */
tnode_free_init(oldtnode); tnode_free_init(oldtnode);
...@@ -621,10 +627,8 @@ static int halve(struct trie *t, struct tnode *oldtnode) ...@@ -621,10 +627,8 @@ static int halve(struct trie *t, struct tnode *oldtnode)
/* Two nonempty children */ /* Two nonempty children */
inode = tnode_new(node0->key, oldtnode->pos, 1); inode = tnode_new(node0->key, oldtnode->pos, 1);
if (!inode) { if (!inode)
tnode_free(tn); goto nomem;
return -ENOMEM;
}
tnode_free_append(tn, inode); tnode_free_append(tn, inode);
/* initialize pointers out of node */ /* initialize pointers out of node */
...@@ -637,9 +641,12 @@ static int halve(struct trie *t, struct tnode *oldtnode) ...@@ -637,9 +641,12 @@ static int halve(struct trie *t, struct tnode *oldtnode)
} }
/* setup the parent pointers into and out of this node */ /* setup the parent pointers into and out of this node */
replace(t, oldtnode, tn); return replace(t, oldtnode, tn);
nomem:
return 0; /* all pointers should be clean so we are done */
tnode_free(tn);
notnode:
return NULL;
} }
static void collapse(struct trie *t, struct tnode *oldtnode) static void collapse(struct trie *t, struct tnode *oldtnode)
...@@ -796,10 +803,14 @@ static bool should_collapse(const struct tnode *tn) ...@@ -796,10 +803,14 @@ static bool should_collapse(const struct tnode *tn)
} }
#define MAX_WORK 10 #define MAX_WORK 10
static void resize(struct trie *t, struct tnode *tn) static struct tnode __rcu **resize(struct trie *t, struct tnode *tn)
{ {
#ifdef CONFIG_IP_FIB_TRIE_STATS
struct trie_use_stats __percpu *stats = t->stats;
#endif
struct tnode *tp = node_parent(tn); struct tnode *tp = node_parent(tn);
struct tnode __rcu **cptr; unsigned long cindex = tp ? get_index(tn->key, tp) : 0;
struct tnode __rcu **cptr = tp ? tp->tnode : &t->trie;
int max_work = MAX_WORK; int max_work = MAX_WORK;
pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n", pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
...@@ -809,52 +820,57 @@ static void resize(struct trie *t, struct tnode *tn) ...@@ -809,52 +820,57 @@ static void resize(struct trie *t, struct tnode *tn)
* doing it ourselves. This way we can let RCU fully do its * doing it ourselves. This way we can let RCU fully do its
* thing without us interfering * thing without us interfering
*/ */
cptr = tp ? &tp->tnode[get_index(tn->key, tp)] : &t->trie; BUG_ON(tn != rtnl_dereference(cptr[cindex]));
BUG_ON(tn != rtnl_dereference(*cptr));
/* Double as long as the resulting node has a number of /* Double as long as the resulting node has a number of
* nonempty nodes that are above the threshold. * nonempty nodes that are above the threshold.
*/ */
while (should_inflate(tp, tn) && max_work) { while (should_inflate(tp, tn) && max_work) {
if (inflate(t, tn)) { struct tnode __rcu **tcptr = inflate(t, tn);
if (!tcptr) {
#ifdef CONFIG_IP_FIB_TRIE_STATS #ifdef CONFIG_IP_FIB_TRIE_STATS
this_cpu_inc(t->stats->resize_node_skipped); this_cpu_inc(stats->resize_node_skipped);
#endif #endif
break; break;
} }
max_work--; max_work--;
tn = rtnl_dereference(*cptr); cptr = tcptr;
tn = rtnl_dereference(cptr[cindex]);
} }
/* Return if at least one inflate is run */ /* Return if at least one inflate is run */
if (max_work != MAX_WORK) if (max_work != MAX_WORK)
return; return cptr;
/* Halve as long as the number of empty children in this /* Halve as long as the number of empty children in this
* node is above threshold. * node is above threshold.
*/ */
while (should_halve(tp, tn) && max_work) { while (should_halve(tp, tn) && max_work) {
if (halve(t, tn)) { struct tnode __rcu **tcptr = halve(t, tn);
if (!tcptr) {
#ifdef CONFIG_IP_FIB_TRIE_STATS #ifdef CONFIG_IP_FIB_TRIE_STATS
this_cpu_inc(t->stats->resize_node_skipped); this_cpu_inc(stats->resize_node_skipped);
#endif #endif
break; break;
} }
max_work--; max_work--;
tn = rtnl_dereference(*cptr); cptr = tcptr;
tn = rtnl_dereference(cptr[cindex]);
} }
/* Only one child remains */ /* Only one child remains */
if (should_collapse(tn)) { if (should_collapse(tn)) {
collapse(t, tn); collapse(t, tn);
return; return cptr;
} }
/* Return if at least one deflate was run */ /* Return if at least one deflate was run */
if (max_work != MAX_WORK) if (max_work != MAX_WORK)
return; return cptr;
/* push the suffix length to the parent node */ /* push the suffix length to the parent node */
if (tn->slen > tn->pos) { if (tn->slen > tn->pos) {
...@@ -863,6 +879,8 @@ static void resize(struct trie *t, struct tnode *tn) ...@@ -863,6 +879,8 @@ static void resize(struct trie *t, struct tnode *tn)
if (tp && (slen > tp->slen)) if (tp && (slen > tp->slen))
tp->slen = slen; tp->slen = slen;
} }
return cptr;
} }
static void leaf_pull_suffix(struct tnode *tp, struct tnode *l) static void leaf_pull_suffix(struct tnode *tp, struct tnode *l)
...@@ -952,16 +970,18 @@ static struct fib_alias *fib_find_alias(struct hlist_head *fah, u8 slen, ...@@ -952,16 +970,18 @@ static struct fib_alias *fib_find_alias(struct hlist_head *fah, u8 slen,
static void trie_rebalance(struct trie *t, struct tnode *tn) static void trie_rebalance(struct trie *t, struct tnode *tn)
{ {
struct tnode *tp; struct tnode __rcu **cptr = &t->trie;
while (tn) { while (tn) {
tp = node_parent(tn); struct tnode *tp = node_parent(tn);
resize(t, tn);
tn = tp; cptr = resize(t, tn);
if (!tp)
break;
tn = container_of(cptr, struct tnode, tnode[0]);
} }
} }
/* only used from updater-side */
static int fib_insert_node(struct trie *t, struct tnode *tp, static int fib_insert_node(struct trie *t, struct tnode *tp,
struct fib_alias *new, t_key key) struct fib_alias *new, t_key key)
{ {
...@@ -969,7 +989,7 @@ static int fib_insert_node(struct trie *t, struct tnode *tp, ...@@ -969,7 +989,7 @@ static int fib_insert_node(struct trie *t, struct tnode *tp,
l = leaf_new(key, new); l = leaf_new(key, new);
if (!l) if (!l)
return -ENOMEM; goto noleaf;
/* retrieve child from parent node */ /* retrieve child from parent node */
if (tp) if (tp)
...@@ -987,10 +1007,8 @@ static int fib_insert_node(struct trie *t, struct tnode *tp, ...@@ -987,10 +1007,8 @@ static int fib_insert_node(struct trie *t, struct tnode *tp,
struct tnode *tn; struct tnode *tn;
tn = tnode_new(key, __fls(key ^ n->key), 1); tn = tnode_new(key, __fls(key ^ n->key), 1);
if (!tn) { if (!tn)
node_free(l); goto notnode;
return -ENOMEM;
}
/* initialize routes out of node */ /* initialize routes out of node */
NODE_INIT_PARENT(tn, tp); NODE_INIT_PARENT(tn, tp);
...@@ -1010,6 +1028,10 @@ static int fib_insert_node(struct trie *t, struct tnode *tp, ...@@ -1010,6 +1028,10 @@ static int fib_insert_node(struct trie *t, struct tnode *tp,
trie_rebalance(t, tp); trie_rebalance(t, tp);
return 0; return 0;
notnode:
node_free(l);
noleaf:
return -ENOMEM;
} }
static int fib_insert_alias(struct trie *t, struct tnode *tp, static int fib_insert_alias(struct trie *t, struct tnode *tp,
...@@ -1642,18 +1664,20 @@ int fib_table_flush(struct fib_table *tb) ...@@ -1642,18 +1664,20 @@ int fib_table_flush(struct fib_table *tb)
/* walk trie in reverse order */ /* walk trie in reverse order */
do { do {
while (!(cindex--)) { while (!(cindex--)) {
struct tnode __rcu **cptr;
t_key pkey = pn->key; t_key pkey = pn->key;
n = pn; n = pn;
pn = node_parent(n); pn = node_parent(n);
/* resize completed node */ /* resize completed node */
resize(t, n); cptr = resize(t, n);
/* if we got the root we are done */ /* if we got the root we are done */
if (!pn) if (!pn)
goto flush_complete; goto flush_complete;
pn = container_of(cptr, struct tnode, tnode[0]);
cindex = get_index(pkey, pn); cindex = get_index(pkey, pn);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment