aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/patches-3.18/080-25-fib_trie-Various-clean-ups-for-handling-slen.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/generic/patches-3.18/080-25-fib_trie-Various-clean-ups-for-handling-slen.patch')
-rw-r--r--target/linux/generic/patches-3.18/080-25-fib_trie-Various-clean-ups-for-handling-slen.patch116
1 files changed, 116 insertions, 0 deletions
diff --git a/target/linux/generic/patches-3.18/080-25-fib_trie-Various-clean-ups-for-handling-slen.patch b/target/linux/generic/patches-3.18/080-25-fib_trie-Various-clean-ups-for-handling-slen.patch
new file mode 100644
index 0000000..c7739d0
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-25-fib_trie-Various-clean-ups-for-handling-slen.patch
@@ -0,0 +1,116 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Thu, 22 Jan 2015 15:51:45 -0800
+Subject: [PATCH] fib_trie: Various clean-ups for handling slen
+
+While doing further work on the fib_trie I noted a few items.
+
+First I was using calls that were far more complicated than they needed to
+be for determining when to push/pull the suffix length. I have updated the
+code to reflect the simplier logic.
+
+The second issue is that I realised we weren't necessarily handling the
+case of a leaf_info struct surviving a flush. I have updated the logic so
+that now we will call pull_suffix in the event of having a leaf info value
+left in the leaf after flushing it.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -917,27 +917,20 @@ static void leaf_push_suffix(struct tnod
+
+ static void remove_leaf_info(struct tnode *l, struct leaf_info *old)
+ {
+- struct hlist_node *prev;
+-
+- /* record the location of the pointer to this object */
+- prev = rtnl_dereference(hlist_pprev_rcu(&old->hlist));
++ /* record the location of the previous list_info entry */
++ struct hlist_node **pprev = old->hlist.pprev;
++ struct leaf_info *li = hlist_entry(pprev, typeof(*li), hlist.next);
+
+ /* remove the leaf info from the list */
+ hlist_del_rcu(&old->hlist);
+
+- /* if we emptied the list this leaf will be freed and we can sort
+- * out parent suffix lengths as a part of trie_rebalance
+- */
+- if (hlist_empty(&l->list))
++ /* only access li if it is pointing at the last valid hlist_node */
++ if (hlist_empty(&l->list) || (*pprev))
+ return;
+
+- /* if we removed the tail then we need to update slen */
+- if (!rcu_access_pointer(hlist_next_rcu(prev))) {
+- struct leaf_info *li = hlist_entry(prev, typeof(*li), hlist);
+-
+- l->slen = KEYLENGTH - li->plen;
+- leaf_pull_suffix(l);
+- }
++ /* update the trie with the latest suffix length */
++ l->slen = KEYLENGTH - li->plen;
++ leaf_pull_suffix(l);
+ }
+
+ static void insert_leaf_info(struct tnode *l, struct leaf_info *new)
+@@ -961,7 +954,7 @@ static void insert_leaf_info(struct tnod
+ }
+
+ /* if we added to the tail node then we need to update slen */
+- if (!rcu_access_pointer(hlist_next_rcu(&new->hlist))) {
++ if (l->slen < (KEYLENGTH - new->plen)) {
+ l->slen = KEYLENGTH - new->plen;
+ leaf_push_suffix(l);
+ }
+@@ -1613,6 +1606,7 @@ static int trie_flush_leaf(struct tnode
+ struct hlist_head *lih = &l->list;
+ struct hlist_node *tmp;
+ struct leaf_info *li = NULL;
++ unsigned char plen = KEYLENGTH;
+
+ hlist_for_each_entry_safe(li, tmp, lih, hlist) {
+ found += trie_flush_list(&li->falh);
+@@ -1620,8 +1614,14 @@ static int trie_flush_leaf(struct tnode
+ if (list_empty(&li->falh)) {
+ hlist_del_rcu(&li->hlist);
+ free_leaf_info(li);
++ continue;
+ }
++
++ plen = li->plen;
+ }
++
++ l->slen = KEYLENGTH - plen;
++
+ return found;
+ }
+
+@@ -1700,13 +1700,22 @@ int fib_table_flush(struct fib_table *tb
+ for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) {
+ found += trie_flush_leaf(l);
+
+- if (ll && hlist_empty(&ll->list))
+- trie_leaf_remove(t, ll);
++ if (ll) {
++ if (hlist_empty(&ll->list))
++ trie_leaf_remove(t, ll);
++ else
++ leaf_pull_suffix(ll);
++ }
++
+ ll = l;
+ }
+
+- if (ll && hlist_empty(&ll->list))
+- trie_leaf_remove(t, ll);
++ if (ll) {
++ if (hlist_empty(&ll->list))
++ trie_leaf_remove(t, ll);
++ else
++ leaf_pull_suffix(ll);
++ }
+
+ pr_debug("trie_flush found=%d\n", found);
+ return found;