aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/patches-3.18/080-17-fib_trie-Remove-checks-for-index-tnode_child_length-.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/generic/patches-3.18/080-17-fib_trie-Remove-checks-for-index-tnode_child_length-.patch')
-rw-r--r--target/linux/generic/patches-3.18/080-17-fib_trie-Remove-checks-for-index-tnode_child_length-.patch95
1 files changed, 95 insertions, 0 deletions
diff --git a/target/linux/generic/patches-3.18/080-17-fib_trie-Remove-checks-for-index-tnode_child_length-.patch b/target/linux/generic/patches-3.18/080-17-fib_trie-Remove-checks-for-index-tnode_child_length-.patch
new file mode 100644
index 0000000..8f7c671
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-17-fib_trie-Remove-checks-for-index-tnode_child_length-.patch
@@ -0,0 +1,95 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:57:02 -0800
+Subject: [PATCH] fib_trie: Remove checks for index >= tnode_child_length
+ from tnode_get_child
+
+For some reason the compiler doesn't seem to understand that when we are in
+a loop that runs from tnode_child_length - 1 to 0 we don't expect the value
+of tn->bits to change. As such every call to tnode_get_child was rerunning
+tnode_chile_length which ended up consuming quite a bit of space in the
+resultant assembly code.
+
+I have gone though and verified that in all cases where tnode_get_child
+is used we are either winding though a fixed loop from tnode_child_length -
+1 to 0, or are in a fastpath case where we are verifying the value by
+either checking for any remaining bits after shifting index by bits and
+testing for leaf, or by using tnode_child_length.
+
+size net/ipv4/fib_trie.o
+Before:
+ text data bss dec hex filename
+ 15506 376 8 15890 3e12 net/ipv4/fib_trie.o
+
+After:
+ text data bss dec hex filename
+ 14827 376 8 15211 3b6b net/ipv4/fib_trie.o
+
+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
+@@ -186,8 +186,6 @@ static inline unsigned long tnode_child_
+ static inline struct tnode *tnode_get_child(const struct tnode *tn,
+ unsigned long i)
+ {
+- BUG_ON(i >= tnode_child_length(tn));
+-
+ return rtnl_dereference(tn->child[i]);
+ }
+
+@@ -195,8 +193,6 @@ static inline struct tnode *tnode_get_ch
+ static inline struct tnode *tnode_get_child_rcu(const struct tnode *tn,
+ unsigned long i)
+ {
+- BUG_ON(i >= tnode_child_length(tn));
+-
+ return rcu_dereference_rtnl(tn->child[i]);
+ }
+
+@@ -371,7 +367,7 @@ static inline int tnode_full(const struc
+ */
+ static void put_child(struct tnode *tn, unsigned long i, struct tnode *n)
+ {
+- struct tnode *chi = rtnl_dereference(tn->child[i]);
++ struct tnode *chi = tnode_get_child(tn, i);
+ int isfull, wasfull;
+
+ BUG_ON(i >= tnode_child_length(tn));
+@@ -867,7 +863,7 @@ static struct tnode *fib_find_node(struc
+ if (IS_LEAF(n))
+ break;
+
+- n = rcu_dereference_rtnl(n->child[index]);
++ n = tnode_get_child_rcu(n, index);
+ }
+
+ return n;
+@@ -934,7 +930,7 @@ static struct list_head *fib_insert_node
+ }
+
+ tp = n;
+- n = rcu_dereference_rtnl(n->child[index]);
++ n = tnode_get_child_rcu(n, index);
+ }
+
+ l = leaf_new(key);
+@@ -1215,7 +1211,7 @@ int fib_table_lookup(struct fib_table *t
+ cindex = index;
+ }
+
+- n = rcu_dereference(n->child[index]);
++ n = tnode_get_child_rcu(n, index);
+ if (unlikely(!n))
+ goto backtrace;
+ }
+@@ -1835,7 +1831,7 @@ static void trie_collect_stats(struct tr
+ if (n->bits < MAX_STAT_DEPTH)
+ s->nodesizes[n->bits]++;
+
+- for (i = 0; i < tnode_child_length(n); i++) {
++ for (i = tnode_child_length(n); i--;) {
+ if (!rcu_access_pointer(n->child[i]))
+ s->nullpointers++;
+ }